Browse Source

vue_admin_action

Panda 4 months ago
parent
commit
f1052d9413
100 changed files with 89375 additions and 7 deletions
  1. 0 1
      .env.sample
  2. 54 0
      application/admin/controller/Vue.php
  3. 46 0
      application/admin/controller/VueDemo.php
  4. 176 0
      application/admin/controller/VueModule.php
  5. 210 0
      application/admin/view/vue_demo/index.html
  6. 42 0
      application/admin/view/vue_layout/main.html
  7. 0 1
      application/config.php
  8. 14 4
      application/extra/addons.php
  9. 119 0
      application/utils/AppResult.php
  10. 33 0
      application/utils/VueAdmin/AdminData.php
  11. 270 1
      public/assets/js/addons.js
  12. 1597 0
      public/assets/v1/app.css
  13. 4915 0
      public/assets/v1/app.js
  14. 0 0
      public/assets/v1/common/js/CryptoJS.js
  15. 1 0
      public/assets/v1/common/js/Sortable.min.js
  16. 27421 0
      public/assets/v1/common/js/aliyun-oss-sdk-6.18.0.min.js
  17. 1 0
      public/assets/v1/common/js/axios.min.js
  18. 8 0
      public/assets/v1/common/js/cookie.min.js
  19. 1 0
      public/assets/v1/common/js/jquery-3.6.0.min.js
  20. 8 0
      public/assets/v1/common/js/particles.min.js
  21. 0 0
      public/assets/v1/common/js/pinyin-pro.js
  22. 5 0
      public/assets/v1/common/js/vue.min.js
  23. 234 0
      public/assets/v1/common/lib/captcha/vue-puzzle-vcode.css
  24. 582 0
      public/assets/v1/common/lib/captcha/vue-puzzle-vcode.js
  25. 34 0
      public/assets/v1/common/lib/echart/echarts.min.js
  26. BIN
      public/assets/v1/common/lib/element-ui/fonts/element-icons.ttf
  27. BIN
      public/assets/v1/common/lib/element-ui/fonts/element-icons.woff
  28. 0 0
      public/assets/v1/common/lib/element-ui/index.css
  29. 0 0
      public/assets/v1/common/lib/element-ui/index.js
  30. 28 0
      public/assets/v1/common/lib/imageEditor/.project
  31. 128 0
      public/assets/v1/common/lib/imageEditor/css/tui-image-editor.css
  32. 231 0
      public/assets/v1/common/lib/imageEditor/index.html
  33. 934 0
      public/assets/v1/common/lib/imageEditor/js/basic.js
  34. 570 0
      public/assets/v1/common/lib/imageEditor/js/mobile.js
  35. 26123 0
      public/assets/v1/common/lib/imageEditor/libs/fabric.js
  36. 3988 0
      public/assets/v1/common/lib/imageEditor/libs/tui-code-snippet.js
  37. 6 0
      public/assets/v1/common/lib/imageEditor/libs/tui-image-editor.min.js
  38. 74 0
      public/assets/v1/common/lib/nprogress/nprogress.css
  39. 499 0
      public/assets/v1/common/lib/nprogress/nprogress.js
  40. 0 0
      public/assets/v1/common/lib/tinymce/icons/default/icons.min.js
  41. 92 0
      public/assets/v1/common/lib/tinymce/jquery.tinymce.min.js
  42. 3 0
      public/assets/v1/common/lib/tinymce/langs/readme.md
  43. 410 0
      public/assets/v1/common/lib/tinymce/langs/zh_CN.js
  44. 8 0
      public/assets/v1/common/lib/tinymce/plugins/advlist/plugin.min.js
  45. 8 0
      public/assets/v1/common/lib/tinymce/plugins/anchor/plugin.min.js
  46. 8 0
      public/assets/v1/common/lib/tinymce/plugins/autolink/plugin.min.js
  47. 9 0
      public/assets/v1/common/lib/tinymce/plugins/autoresize/plugin.min.js
  48. 8 0
      public/assets/v1/common/lib/tinymce/plugins/autosave/plugin.min.js
  49. 55 0
      public/assets/v1/common/lib/tinymce/plugins/ax_wordlimit/plugin.js
  50. 55 0
      public/assets/v1/common/lib/tinymce/plugins/ax_wordlimit/plugin.min.js
  51. 8 0
      public/assets/v1/common/lib/tinymce/plugins/bbcode/plugin.min.js
  52. 79 0
      public/assets/v1/common/lib/tinymce/plugins/bdmap/bd.html
  53. 124 0
      public/assets/v1/common/lib/tinymce/plugins/bdmap/map.html
  54. 70 0
      public/assets/v1/common/lib/tinymce/plugins/bdmap/plugin.js
  55. 70 0
      public/assets/v1/common/lib/tinymce/plugins/bdmap/plugin.min.js
  56. 8 0
      public/assets/v1/common/lib/tinymce/plugins/charmap/plugin.min.js
  57. 9 0
      public/assets/v1/common/lib/tinymce/plugins/code/plugin.min.js
  58. 8 0
      public/assets/v1/common/lib/tinymce/plugins/codesample/plugin.min.js
  59. 9 0
      public/assets/v1/common/lib/tinymce/plugins/colorpicker/plugin.min.js
  60. 9 0
      public/assets/v1/common/lib/tinymce/plugins/contextmenu/plugin.min.js
  61. 8 0
      public/assets/v1/common/lib/tinymce/plugins/directionality/plugin.min.js
  62. 9424 0
      public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojiimages.js
  63. 2 0
      public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojiimages.min.js
  64. 9423 0
      public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojis.js
  65. 1 0
      public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojis.min.js
  66. 8 0
      public/assets/v1/common/lib/tinymce/plugins/emoticons/plugin.min.js
  67. 8 0
      public/assets/v1/common/lib/tinymce/plugins/fullpage/plugin.min.js
  68. 8 0
      public/assets/v1/common/lib/tinymce/plugins/fullscreen/plugin.min.js
  69. 52 0
      public/assets/v1/common/lib/tinymce/plugins/gallery/plugin.js
  70. 41 0
      public/assets/v1/common/lib/tinymce/plugins/gallery/plugin.min.js
  71. 8 0
      public/assets/v1/common/lib/tinymce/plugins/help/plugin.min.js
  72. 9 0
      public/assets/v1/common/lib/tinymce/plugins/hr/plugin.min.js
  73. 8 0
      public/assets/v1/common/lib/tinymce/plugins/image/plugin.min.js
  74. 8 0
      public/assets/v1/common/lib/tinymce/plugins/imagetools/plugin.min.js
  75. 8 0
      public/assets/v1/common/lib/tinymce/plugins/importcss/plugin.min.js
  76. 8 0
      public/assets/v1/common/lib/tinymce/plugins/insertdatetime/plugin.min.js
  77. 8 0
      public/assets/v1/common/lib/tinymce/plugins/legacyoutput/plugin.min.js
  78. 8 0
      public/assets/v1/common/lib/tinymce/plugins/link/plugin.min.js
  79. 8 0
      public/assets/v1/common/lib/tinymce/plugins/lists/plugin.min.js
  80. 595 0
      public/assets/v1/common/lib/tinymce/plugins/media/plugin.min.js
  81. 9 0
      public/assets/v1/common/lib/tinymce/plugins/nonbreaking/plugin.min.js
  82. 9 0
      public/assets/v1/common/lib/tinymce/plugins/noneditable/plugin.min.js
  83. 9 0
      public/assets/v1/common/lib/tinymce/plugins/pagebreak/plugin.min.js
  84. 8 0
      public/assets/v1/common/lib/tinymce/plugins/paste/plugin.min.js
  85. 9 0
      public/assets/v1/common/lib/tinymce/plugins/preview/plugin.min.js
  86. 9 0
      public/assets/v1/common/lib/tinymce/plugins/print/plugin.min.js
  87. 8 0
      public/assets/v1/common/lib/tinymce/plugins/quickbars/plugin.min.js
  88. 9 0
      public/assets/v1/common/lib/tinymce/plugins/save/plugin.min.js
  89. 8 0
      public/assets/v1/common/lib/tinymce/plugins/searchreplace/plugin.min.js
  90. 8 0
      public/assets/v1/common/lib/tinymce/plugins/spellchecker/plugin.min.js
  91. 9 0
      public/assets/v1/common/lib/tinymce/plugins/tabfocus/plugin.min.js
  92. 8 0
      public/assets/v1/common/lib/tinymce/plugins/table/plugin.min.js
  93. 8 0
      public/assets/v1/common/lib/tinymce/plugins/template/plugin.min.js
  94. 9 0
      public/assets/v1/common/lib/tinymce/plugins/textcolor/plugin.min.js
  95. 8 0
      public/assets/v1/common/lib/tinymce/plugins/textpattern/plugin.min.js
  96. 8 0
      public/assets/v1/common/lib/tinymce/plugins/toc/plugin.min.js
  97. 177 0
      public/assets/v1/common/lib/tinymce/plugins/toolbarsticky/plugin.js
  98. 0 0
      public/assets/v1/common/lib/tinymce/plugins/toolbarsticky/plugin.min.js
  99. 9 0
      public/assets/v1/common/lib/tinymce/plugins/visualblocks/plugin.min.js
  100. 8 0
      public/assets/v1/common/lib/tinymce/plugins/visualchars/plugin.min.js

+ 0 - 1
.env.sample

@@ -1,6 +1,5 @@
 [app]
 debug = true
-trace = true
 
 [database]
 hostname = 127.0.0.1

+ 54 - 0
application/admin/controller/Vue.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\common\controller\Backend;
+use app\utils\AppResult;
+use think\Db;
+use think\exception\DbException;
+use think\response\Json;
+
+/**
+ * vue 页面控制
+ *
+ * @icon fa fa-circle-o
+ */
+class Vue extends Backend
+{
+    protected $noNeedRight = '*';
+
+    /**
+     * 菜单操作按钮
+     *
+     * @return string|Json
+     * @throws \think\Exception
+     * @throws DbException
+     */
+    public function operationPermissions()
+    {
+        // post请求获取数据
+        $params = $this->request->param();
+        $role = $this->auth->getRuleIds()[0] ?? '';
+        $menu_rule  = $params['menu_rule'];
+        $menu_id  = Db::name('auth_rule')->where('name', $menu_rule)->where('ismenu', 1)->value('id');
+        $btn_list = Db::name('auth_rule')->where('pid', $menu_id)->where('ismenu', 0);
+        if ($role != '*') {
+            $role_menus_ids = explode(',',$role);
+            $btn_list->whereIn('id', $role_menus_ids);
+        }
+        $btn_list = $btn_list->where('status', 'normal')->field(['id', 'title as name', 'name as path', 'name as action', 'icon'])->select();
+        $btn      = [];
+        foreach ($btn_list as $value) {
+            $action = explode('/',$value['action']);
+            $action = end($action);
+            $btn[$action] = [
+                'name'   => $value['name'],
+                'path'   => $value['path'],
+                'action' => $action,
+                'icon'   => $value['icon'],
+            ];
+        }
+
+        return AppResult::response200('success', $btn);
+    }
+}

+ 46 - 0
application/admin/controller/VueDemo.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\common\model\UserModel;
+use App\Utils\AppResult;
+
+/**
+ * Admin 模块父级
+ * Module 接管 CURD 公共操作
+ * Class ModuleController
+ * @package App\Http\Controllers\Framework
+ */
+class VueDemo extends VueModule
+{
+    public function callAction($method, $parameters = [])
+    {
+        // 获取请求参数 用于二次处理
+        $params      = $this->params;
+        $this->model = new UserModel();
+        // 根据不同方法处理一些业务
+        switch ($method) {
+            case 'index':
+                // 请求类型是否为POST
+                if ($this->isPost) {
+                    // 条件语句
+                    if (!empty($params['keyword'])) $this->model->where('title', 'like', "%{$params['keyword']}%");
+                    if (!empty($params['status'])) $this->model->where('status', $params['status']);
+                }
+                break;
+//            case 'insert':
+//                break;
+//            case 'update':
+//                break;
+            default:
+                break;
+        }
+
+        return parent::callAction($method, $parameters); // TODO: Change the autogenerated stub
+    }
+
+    public function __construct(array $attributes = [])
+    {
+        parent::__construct();
+    }
+}

+ 176 - 0
application/admin/controller/VueModule.php

@@ -0,0 +1,176 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\common\controller\Backend;
+use app\utils\AppResult;
+use app\utils\DataUtil;
+use app\utils\VueAdmin\AdminData;
+use think\Request;
+
+/**
+ * Admin 模块父级
+ * Module 接管 CURD 公共操作
+ * Class ModuleController
+ * @package App\Http\Controllers\Framework
+ */
+class VueModule extends Backend
+{
+    protected       $model;  // 在子类中赋值
+    protected array $params       = [];    // 请求参数
+    protected array $unset_fields = ['status'];    // 初始化隐藏字段
+    protected int   $statusValue  = 2;    // 状态默认值
+    protected bool  $isPost;              // 请求类型是否为POST
+
+    public function __construct(Request $request = null)
+    {
+        parent::__construct($request);
+        $this->isPost = $this->request->isPost();
+        $this->params = $this->request->param();
+        // 前置操作
+        $this->callAction($this->request->action(), $this->request->param());
+    }
+
+    /**
+     * Execute an action on the controller.
+     *
+     * @param $method
+     * @param $parameters
+     * @return mixed
+     */
+    public function callAction($method, $parameters = [])
+    {
+        return $this->{$method}(...array_values($parameters));
+    }
+
+    /**
+     * 列表页
+     * @return string|\think\response\Json
+     * @throws \think\Exception
+     */
+    public function index()
+    {
+        if ($this->isPost) {
+            $params = $this->params;
+
+            $query = $this->model;
+
+            // 自动排序
+            if ($orderBy = AdminData::orderBy()) {
+                foreach ($orderBy as $order) {
+                    $query->order($order['sort'], $order['orderBy']);
+                }
+            }
+
+            if (!isset($params['page'])) {
+                $list = $query->select();
+            } else {
+                $list = $query->paginate($params['size'] ?? 15);
+            }
+
+            return AppResult::response200('success', $list);
+        } else {
+            return $this->view->fetch();
+        }
+    }
+
+    /**
+     * 添加
+     * @return string
+     */
+    public function insert()
+    {
+        $params = $this->params;
+
+        // 初始化空数据
+        $form                = DataUtil::field($params, $this->unset_fields);
+        $form['status']      = $this->statusValue;
+        $form['create_time'] = time();
+        if (!$this->model->insert($form)) {
+            return AppResult::response201('创建失败');
+        }
+        return AppResult::response200('创建成功');
+    }
+
+    /**
+     * 修改
+     * @return string
+     */
+    public function update()
+    {
+        $params = $this->params;
+        if (empty($params['id'])) {
+            return AppResult::response203('操作超时!');
+        }
+
+        // 初始化空数据
+        $form                = DataUtil::field($params, array_merge(['is_system'], $this->unset_fields));
+        $form['update_time'] = time();
+        if (!$this->model->where('id', $params['id'])->update($form)) {
+            return AppResult::response201('操作失败');
+        }
+        return AppResult::response200('操作成功');
+    }
+
+    /**
+     * 状态
+     * @return string
+     */
+    public function status()
+    {
+        $params = $this->params;
+        if (empty($params['id']) || !isset($params['status'])) {
+            return AppResult::response203('操作超时!');
+        }
+
+        $form['status']      = $params['status'] == 1 ? 2 : 1;
+        $form['update_time'] = time();
+        if (!$this->model->where('id', $params['id'])->update($form)) {
+            return AppResult::response201('操作失败');
+        }
+        return AppResult::response200('操作成功');
+    }
+
+    /**
+     * 删除
+     * @return string
+     */
+    public function remove()
+    {
+        $params = $this->params;
+        if (empty($params['id'])) {
+            return AppResult::response203('操作超时!');
+        }
+
+//        $form['delete_time'] = time();
+//        $form['update_time'] = time();
+//        if (!$this->model->where('id', $params['id'])->update($form)) {
+//            return AppResult::response201('操作失败');
+//        }
+        if (!$this->model->where('id', $params['id'])->delete()) {
+            return AppResult::response201('操作失败');
+        }
+        return AppResult::response200('操作成功');
+    }
+
+    /**
+     * 排序
+     * @return string
+     */
+    public function rank()
+    {
+        $params = $this->params;
+        if (!isset($params['id']) || !isset($params['weigh'])) {
+            return AppResult::response203('操作超时!');
+        }
+
+        $form['weigh']       = $params['weigh'];
+        $form['update_time'] = time();
+
+        if (!$this->model->where('id', $params['id'])->update($form)) {
+            return AppResult::response201('操作失败');
+        }
+
+        return AppResult::response200('操作成功');
+    }
+}

+ 210 - 0
application/admin/view/vue_demo/index.html

@@ -0,0 +1,210 @@
+{extend name="vue_layout/main" /}
+{block name="styles"}
+<style>
+    .Va-container-content {
+        height: 72vw;
+    }
+
+    .icons-type-list {
+        width: 350px;
+        overflow: hidden;
+        padding: 0;
+    }
+
+    .icons-type-one {
+        border-radius: unset !important;
+        border: 1px solid #ccc;
+        padding: 10px 10px;
+        margin: 2px;
+    }
+
+    .icons-type-list .icons-type-one.is-checked {
+        border: 1px solid var(--buttonHoverColors);
+    }
+</style>
+{/block}
+
+<!-- 主体 -->
+{block name="content"}
+<div class="form-container" style="overflow: hidden">
+    <div class="form-container-header">
+        <el-form :inline="true" :model="tables.search" size="small">
+            <el-form-item>
+                <el-input v-model="tables.search.deviceCode" placeholder="按设备号搜索" clearable></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-input v-model="tables.search.deviceType" placeholder="按设备型号搜索" clearable></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-input v-model="tables.search.watchName" placeholder="按设备名称搜索" clearable></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-select v-model="tables.search.activationStatus" placeholder="-- 按状态搜索 --" clearable>
+                    <el-option label="状态(全部)" value=""></el-option>
+                    <el-option key="0" label="未激活" value="0"></el-option>
+                    <el-option key="1" label="已激活" value="1"></el-option>
+                </el-select>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button type="primary" size="small" @click="tablesSearchEvent"><i class="fa fa-search"></i> 搜 索
+                </el-button>
+                <el-button size="small" @click="tablesResetsEvent"><i class="fa fa-refresh"></i> 重 置</el-button>
+            </el-form-item>
+
+        </el-form>
+    </div>
+    <div class="form-container-main inline-tables no-pic" v-loading="tables.options.loading">
+        <el-table
+                :data="tables.data"
+                border
+                :stripe="true"
+                @selection-change="tablesSelectChange"
+                @sort-change="tablesPaginationSortChange"
+                @cell-click="tablesCellMoveEvent"
+                tooltip-effect="dark"
+                ref="formContainerTables"
+                row-key="id">
+            <el-table-column prop="id" label="#ID" align="center" width="60"></el-table-column>
+            <el-table-column prop="avatar" label="头像" align="center" width="80">
+                <template slot-scope="scope">
+                    <va-image :src="scope.row.avatar" :key="scope.row.avatar" class="tables-image"></va-image>
+                </template>
+            </el-table-column>
+            <el-table-column prop="nickname" label="昵称" align="center" width="100"></el-table-column>
+            <el-table-column prop="mobile" label="手机号" align="center" width="100"></el-table-column>
+
+            <el-table-column prop="gender" label="性别" align="center" width="60">
+                <template slot-scope="scope">
+                    <el-tag v-if="scope.row.gender == 0" size="mini" type="danger" effect="plain">女</el-tag>
+                    <el-tag v-if="scope.row.gender == 1" size="mini" type="success" effect="plain">男</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="birthday_type" label="生日类型" align="center" width="80">
+                <template slot-scope="scope">
+                    <el-tag v-if="scope.row.birthday_type == 1" size="mini" type="danger" effect="plain">阴历</el-tag>
+                    <el-tag v-if="scope.row.birthday_type == 2" size="mini" type="success" effect="plain">阳历</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="birthday" label="生日" align="center"></el-table-column>
+
+            <el-table-column prop="watch_id" label="手表用户ID" align="center"></el-table-column>
+            <el-table-column prop="watch_no" label="手表编号" align="center"></el-table-column>
+            <el-table-column prop="watch_activation_no" label="手表激活码" align="center"></el-table-column>
+            <el-table-column prop="watch_bind_time" label="手表绑定时间" align="center" :formatter="formatTableDate" width="160" sortable></el-table-column>
+            <el-table-column prop="watch_end_time" label="手表到期时间" align="center" :formatter="formatTableDate" width="160" sortable></el-table-column>
+
+            <el-table-column prop="urgent" label="紧急联系人姓名" align="center"></el-table-column>
+            <el-table-column prop="urgent_phone" label="紧急联系人手机号" align="center"></el-table-column>
+            <el-table-column prop="urgent_relation" label="紧急联系人关系" align="center"></el-table-column>
+            <el-table-column prop="province" label="省" align="center"></el-table-column>
+            <el-table-column prop="city" label="市" align="center"></el-table-column>
+            <el-table-column prop="district" label="区" align="center"></el-table-column>
+            <el-table-column prop="area" label="地址详情" align="center"></el-table-column>
+            <el-table-column prop="options" label="操作" align="left" fixed="right" width="160">
+                <template slot-scope="scope">
+                    <el-button size="mini" warning type="text" @click="tablesRowsUpdate(scope.row)" v-if="permissions.update">
+                        <i :class="permissions.update.icon"></i> {{permissions.update.name}}
+                    </el-button>
+                    <!-- 更多操作 -->
+                    <el-dropdown size="small" style="margin-left: 10px">
+                        <el-button size="mini" primary type="text"><i class="fa fa-reorder "></i> 更多操作<i
+                                class="el-icon-arrow-down el-icon--right"></i></el-button>
+                        <el-dropdown-menu slot="dropdown">
+                            <el-dropdown-item v-if="permissions.status">
+                                <el-button size="mini" warning type="text"
+                                           @click="tablesRowsStatus(scope.row,{id:scope.row.id})"
+                                           v-if="permissions.status" :disabled="scope.row.is_system==1">
+                                    <i :class="permissions.status.icon"></i>
+                                    {{tables.status.maps[scope.row.status]}}
+                                </el-button>
+                            </el-dropdown-item>
+
+                            <el-dropdown-item v-if="permissions.remove">
+                                <el-button size="mini" danger type="text" @click="tablesRowsRemove(scope.row)"
+                                           v-if="permissions.remove" :disabled="scope.row.is_system==1">
+                                    <i :class="permissions.remove.icon"></i> {{permissions.remove.name}}
+                                </el-button>
+                            </el-dropdown-item>
+                        </el-dropdown-menu>
+                    </el-dropdown>
+                    <!-- 更多操作 End. -->
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="Va-container-tables-pagination-box"><el-pagination
+                class="Va-container-tables-pagination"
+                @size-change="tablesPaginationSizeChange"
+                @current-change="tablesPaginationCurrentChange"
+                :current-page.sync="tables.pagination.page"
+                :page-sizes="tables.pagination.sizes"
+                :page-size="tables.pagination.size"
+                :layout="tables.pagination.layouts"
+                :total="tables.pagination.total"
+                data-7512a93d>
+        </el-pagination></div>
+    </div>
+</div>
+{/block}
+
+<!-- vue -->
+{block name="scripts"}
+<script>
+    var $App = new Vue({
+        el: '#app',
+        mixins: [$Config, $Layouts, $Tables, $DialogForms],
+        data: {
+            menuRule:'vue_demo',
+            component: {status: false},
+            config: {permissions: true},
+            tables: {
+                remove: {
+                    url: 'remove', msg: '确认删除当前数据吗?', field: 'id'
+                },
+                status: {
+                    url: 'status', field: 'status'
+                },
+                sort: {
+                    url: 'rank', item: 'sort', field: 'id'
+                },
+                url: 'vue_demo',
+                search: {},
+                pagination: {
+                    layout: ''
+                },
+                prop: 'id', orderBy: 'desc'
+            },
+
+        },
+        methods: {
+            tablesRowsInsert() {
+                var that = this;
+                that.create.action = 'insert';
+                that.create.model = {name: '', sort: 255};
+                that.dialogFormsOpens('create');
+            },
+
+            tablesRowsUpdate(rows) {
+                var that = this;
+                that.create.action = 'update';
+                that.create.model = {
+                    id: rows.id,
+                    name: rows.name,
+                    sort: rows.sort,
+                };
+                that.dialogFormsOpens('create');
+            },
+
+            tablesResetsEvent() {
+                var that = this;
+                that.tables.search = {keyword: '', status: ''};
+                that.tablesGetTableList();
+            },
+        },
+        created() {
+        },
+        mounted() {
+        }
+    })
+</script>
+{/block}

+ 42 - 0
application/admin/view/vue_layout/main.html

@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>康年</title>
+    <meta name="keywords" content="" />
+    <meta name="description" content="" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
+    <!-- import css -->
+    <link rel="stylesheet" href="/assets/v1/css/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/assets/v1/common/lib/element-ui/index.css">
+    <link rel="stylesheet" href='/assets/v1/common/lib/nprogress/nprogress.css'>
+    <link rel="stylesheet" href="/assets/v1/common/style/ali-icon/iconfont.css">
+    <link rel="stylesheet" href="/assets/v1/app.css">
+    {block name="styles"}{/block}
+</head>
+<body>
+<!--{literal}-->
+<section id="app" v-cloak class="page-container">
+    <div class="main-content">
+        <div style="overflow: hidden;">
+            {block name="content"}{/block}
+        </div>
+    </div>
+</section>
+<!-- import JavaScript -->
+<script src="/assets/v1/common/js/jquery-3.6.0.min.js"></script>
+<script src="/assets/v1/common/js/vue.min.js"></script>
+<script src="/assets/v1/common/js/CryptoJS.js"></script>
+<script src="/assets/v1/common/js/Sortable.min.js"></script>
+<script src="/assets/v1/common/lib/element-ui/index.js"></script>
+<script src='/assets/v1/common/lib/tinymce/tinymce.min.js'></script>
+<script src='/assets/v1/common/lib/nprogress/nprogress.js'></script>
+<script src="/assets/v1/common/style/ali-icon/iconfont.js"></script>
+<script src="/assets/v1/common/js/cookie.min.js"></script>
+<script src="/assets/v1/common/js/aliyun-oss-sdk-6.18.0.min.js"></script>
+<script src="/assets/v1/common/js/pinyin-pro.js"></script>
+<script src="/assets/v1/app.js"></script>
+{block name="scripts"}{/block}
+<!--{/literal}-->
+</body>
+</html>

+ 0 - 1
application/config.php

@@ -22,7 +22,6 @@ return [
     'app_debug'              => true,
     // 应用Trace
     'app_trace'              => Env::get('app.trace', false),
-    'app_trace'              => false,
     // 应用模式状态
     'app_status'             => '',
     // 是否支持多模块

+ 14 - 4
application/extra/addons.php

@@ -3,6 +3,20 @@
 return [
     'autoload' => false,
     'hooks' => [
+        'app_init' => [
+            'cos',
+            'qrcode',
+            'shopro',
+        ],
+        'module_init' => [
+            'cos',
+        ],
+        'upload_config_init' => [
+            'cos',
+        ],
+        'upload_delete' => [
+            'cos',
+        ],
         'epay_config_init' => [
             'epay',
         ],
@@ -15,10 +29,6 @@ return [
         'user_sidenav_after' => [
             'poster',
         ],
-        'app_init' => [
-            'qrcode',
-            'shopro',
-        ],
         'upgrade' => [
             'shopro',
         ],

+ 119 - 0
application/utils/AppResult.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace app\utils;
+
+/**
+ * Author:Panda
+ * Email:joeyoung0314@qq.com
+ * Class AppResult
+ * @package App\Utils
+ */
+class AppResult
+{
+
+    /**==============应用返回封装==============**/
+
+    /**
+     * 成功返回200
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response200(string $message = 'success', $result = null): string
+    {
+        return self::response(200, $message, $result);
+    }
+
+    /**
+     * 失败返回201
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response201(string $message = 'error', $result = null): string
+    {
+        return self::response(201, $message, $result);
+    }
+
+    /**
+     * 参数缺失返回203
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response203(string $message = 'error', $result = null): string
+    {
+        return self::response(203, $message, $result);
+    }
+
+    /**
+     * 授权无用户返回204
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response204(string $message = '暂无此用户,请先授权手机号,并登录', $result = null): string
+    {
+        return self::response(204, $message, $result);
+    }
+
+    /**
+     * 请求次数过多返回206
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response206(string $message = '请求次数过多', $result = null): string
+    {
+        return self::response(206, $message, $result);
+    }
+
+    /**
+     * 身份信息已过期400
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response400(string $message = 'Identity is overdue', $result = null): string
+    {
+        return self::response(400, $message, $result);
+    }
+
+    /**
+     * 致命错误500
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response500(string $message = 'Fatal error', $result = null): string
+    {
+        return self::response(500, $message, $result);
+    }
+
+    /**
+     * 权限未拥有777
+     * @param string $message
+     * @param $result
+     * @return string json
+     */
+    public static function response777(string $message = 'No Access', $result = null): string
+    {
+        return self::response(777, $message, $result);
+    }
+
+    /**
+     * 返回统一格式
+     * @param int $code
+     * @param string $message
+     * @param $result
+     * @return string
+     */
+    public static function response(int $code, string $message = 'success', $result = null): string
+    {
+        return json_encode([
+            'code'    => $code,
+            'message' => $message,
+            'result'  => $result
+        ], JSON_UNESCAPED_UNICODE);
+    }
+}

+ 33 - 0
application/utils/VueAdmin/AdminData.php

@@ -0,0 +1,33 @@
+<?php
+namespace app\utils\VueAdmin;
+
+use think\Request;
+
+class AdminData {
+    public static function orderBy($default = '')
+    {
+        $sorts = Request::instance()->param('prop');
+        $orders = Request::instance()->param('orderBy', 'desc');
+        $orders = $orders == 'asc' ? 'asc' :'desc';
+
+        $order = [];
+        if(!($sorts) || $sorts == 'null' ||  $sorts == 'undefined')
+        {
+            if($default = explode(',', $default))
+            {
+                if(isset($default[1]) && $default[0] && $default[1]) {
+                    $order[] = ['sort'=>$default[0], 'orderBy'=>$default[1]];
+                }
+            }
+        }else{
+            $sorts = explode(',',$sorts);
+            foreach ($sorts as $sort){
+                $order[] = [
+                    'sort' => $sort,
+                    'orderBy' => $orders
+                ];
+            }
+        }
+        return $order;
+    }
+}

+ 270 - 1
public/assets/js/addons.js

@@ -1,5 +1,274 @@
 define([], function () {
-    require.config({
+    if (typeof Config.upload.storage !== 'undefined' && Config.upload.storage === 'cos') {
+    require(['upload'], function (Upload) {
+        //获取文件MD5值
+        var getFileMd5 = function (file, cb) {
+            //如果savekey中未检测到md5,则无需获取文件md5,直接返回upload的uuid
+            if (!Config.upload.savekey.match(/\{(file)?md5\}/)) {
+                cb && cb(file.upload.uuid);
+                return;
+            }
+            require(['../addons/cos/js/spark'], function (SparkMD5) {
+                var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
+                    chunkSize = 10 * 1024 * 1024,
+                    chunks = Math.ceil(file.size / chunkSize),
+                    currentChunk = 0,
+                    spark = new SparkMD5.ArrayBuffer(),
+                    fileReader = new FileReader();
+
+                fileReader.onload = function (e) {
+                    spark.append(e.target.result);
+                    currentChunk++;
+                    if (currentChunk < chunks) {
+                        loadNext();
+                    } else {
+                        cb && cb(spark.end());
+                    }
+                };
+
+                fileReader.onerror = function () {
+                    console.warn('文件读取错误');
+                };
+
+                function loadNext() {
+                    var start = currentChunk * chunkSize,
+                        end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
+
+                    fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
+                }
+
+                loadNext();
+            });
+        };
+
+        var _onInit = Upload.events.onInit;
+        //初始化中完成判断
+        Upload.events.onInit = function () {
+            _onInit.apply(this, Array.prototype.slice.apply(arguments));
+            //如果上传接口不是COS,则不处理
+            if (this.options.url !== Config.upload.uploadurl) {
+                return;
+            }
+            $.extend(this.options, {
+                //关闭自动处理队列功能
+                autoQueue: false,
+                params: function (files, xhr, chunk) {
+                    var params = Config.upload.multipart;
+                    if (chunk) {
+                        return $.extend({}, params, {
+                            filesize: chunk.file.size,
+                            filename: chunk.file.name,
+                            chunkid: chunk.file.upload.uuid,
+                            chunkindex: chunk.index,
+                            chunkcount: chunk.file.upload.totalChunkCount,
+                            chunkfilesize: chunk.dataBlock.data.size,
+                            chunksize: this.options.chunkSize,
+                            width: chunk.file.width || 0,
+                            height: chunk.file.height || 0,
+                            type: chunk.file.type,
+                            uploadId: chunk.file.uploadId,
+                            key: chunk.file.key,
+                        });
+                    } else {
+                        params = $.extend({}, params, files[0].params);
+                        params.category = files[0].category || '';
+                    }
+                    return params;
+                },
+                chunkSuccess: function (chunk, file, response) {
+                    var etag = chunk.xhr.getResponseHeader("ETag").replace(/(^")|("$)/g, '');
+                    file.etags = file.etags ? file.etags : [];
+                    file.etags[chunk.index] = etag;
+                },
+                chunksUploaded: function (file, done) {
+                    var that = this;
+
+                    Fast.api.ajax({
+                        url: "/addons/cos/index/upload",
+                        data: {
+                            action: 'merge',
+                            filesize: file.size,
+                            filename: file.name,
+                            chunkid: file.upload.uuid,
+                            chunkcount: file.upload.totalChunkCount,
+                            md5: file.md5,
+                            key: file.key,
+                            uploadId: file.uploadId,
+                            etags: file.etags,
+                            category: file.category || '',
+                            costoken: Config.upload.multipart.costoken,
+                        },
+                    }, function (data, ret) {
+                        done(JSON.stringify(ret));
+                        return false;
+                    }, function (data, ret) {
+                        file.accepted = false;
+                        that._errorProcessing([file], ret.msg);
+                        return false;
+                    });
+
+                },
+            });
+
+            var _success = this.options.success;
+            //先移除已有的事件
+            this.off("success", _success).on("success", function (file, response) {
+                var ret = {code: 0, msg: response};
+                try {
+                    if (response) {
+                        ret = typeof response === 'string' ? JSON.parse(response) : response;
+                    }
+                    if (file.xhr.status === 200 || file.xhr.status === 204) {
+                        if (Config.upload.uploadmode === 'client') {
+                            ret = {code: 1, data: {url: '/' + file.key}};
+                        }
+
+                        if (ret.code == 1) {
+                            var url = ret.data.url || '';
+                            Fast.api.ajax({
+                                url: "/addons/cos/index/notify",
+                                data: {name: file.name, url: url, md5: file.md5, size: file.size, width: file.width || 0, height: file.height || 0, type: file.type, category: file.category || '', costoken: Config.upload.multipart.costoken}
+                            }, function () {
+                                return false;
+                            }, function () {
+                                return false;
+                            });
+                        } else {
+                            console.error(ret);
+                        }
+                    } else {
+                        console.error(file.xhr);
+                    }
+                } catch (e) {
+                    console.error(e);
+                }
+                _success.call(this, file, ret);
+            });
+
+            this.on("addedfile", function (file) {
+                var that = this;
+                setTimeout(function () {
+                    if (file.status === 'error') {
+                        return;
+                    }
+                    getFileMd5(file, function (md5) {
+                        var chunk = that.options.chunking && file.size > that.options.chunkSize ? 1 : 0;
+                        var params = $(that.element).data("params") || {};
+                        var category = typeof params.category !== 'undefined' ? params.category : ($(that.element).data("category") || '');
+                        category = typeof category === 'function' ? category.call(that, file) : category;
+                        Fast.api.ajax({
+                            url: "/addons/cos/index/params",
+                            data: {method: 'POST', category: category, md5: md5, name: file.name, type: file.type, size: file.size, chunk: chunk, chunksize: that.options.chunkSize, costoken: Config.upload.multipart.costoken},
+                        }, function (data) {
+                            file.md5 = md5;
+                            file.id = data.id;
+                            file.key = data.key;
+                            file.date = data.date;
+                            file.uploadId = data.uploadId;
+                            file.policy = data.policy;
+                            file.signature = data.signature;
+                            file.partsAuthorization = data.partsAuthorization;
+                            file.params = data;
+                            file.category = category;
+
+                            if (file.status != 'error') {
+                                //开始上传
+                                that.enqueueFile(file);
+                            } else {
+                                that.removeFile(file);
+                            }
+                            return false;
+                        }, function () {
+                            that.removeFile(file);
+                        });
+                    });
+                }, 0);
+            });
+
+
+            if (Config.upload.uploadmode === 'client') {
+                var _method = this.options.method;
+                var _url = this.options.url;
+                this.options.method = function (files) {
+                    if (files[0].upload.chunked) {
+                        var chunk = null;
+                        files[0].upload.chunks.forEach(function (item) {
+                            if (item.status === 'uploading') {
+                                chunk = item;
+                            }
+                        });
+                        if (!chunk) {
+                            return "POST";
+                        } else {
+                            return "PUT";
+                        }
+                    }
+                    return _method;
+                };
+                this.options.url = function (files) {
+                    if (files[0].upload.chunked) {
+                        var chunk = null;
+                        files[0].upload.chunks.forEach(function (item) {
+                            if (item.status === 'uploading') {
+                                chunk = item;
+                            }
+                        });
+                        var index = chunk.dataBlock.chunkIndex;
+                        // debugger;
+                        this.options.headers = {"Authorization": files[0]['partsAuthorization'][index], "x-date": files[0]['date']};
+                        if (!chunk) {
+                            return Config.upload.uploadurl + "/" + files[0].key + "?uploadId=" + files[0].uploadId;
+                        } else {
+                            return Config.upload.uploadurl + "/" + files[0].key + "?partNumber=" + (index + 1) + "&uploadId=" + files[0].uploadId;
+                        }
+                    }
+                    return _url;
+                };
+                this.options.params = function (files, xhr, chunk) {
+                    var params = Config.upload.multipart;
+                    if (chunk) {
+                        return $.extend({}, params, {
+                            filesize: chunk.file.size,
+                            filename: chunk.file.name,
+                            chunkid: chunk.file.upload.uuid,
+                            chunkindex: chunk.index,
+                            chunkcount: chunk.file.upload.totalChunkCount,
+                            chunkfilesize: chunk.dataBlock.data.size,
+                            width: chunk.file.width || 0,
+                            height: chunk.file.height || 0,
+                            type: chunk.file.type,
+                        });
+                    } else {
+                        var retParams = $.extend({}, params, files[0].params || {});
+                        delete retParams.costoken;
+                        return retParams;
+                    }
+                };
+                this.on("sending", function (file, xhr, formData) {
+                    var that = this;
+                    if (file.upload.chunked) {
+                        var _send = xhr.send;
+                        xhr.send = function () {
+                            var chunk = null;
+                            file.upload.chunks.forEach(function (item) {
+                                if (item.status == 'uploading') {
+                                    chunk = item;
+                                }
+                            });
+                            if (chunk) {
+                                _send.call(xhr, chunk.dataBlock.data);
+                            }
+                        };
+                    } else {
+
+                    }
+                });
+            }
+        };
+    });
+}
+
+require.config({
     paths: {
         'designer': '../addons/poster/js/designer',
         'jquery.contextMenu': '../addons/poster/js/jquery.contextMenu',

+ 1597 - 0
public/assets/v1/app.css

@@ -0,0 +1,1597 @@
+* {
+    margin: 0;
+    -webkit-box-sizing: inherit;
+    box-sizing: inherit;
+    font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
+}
+
+img {
+    transition: all 0.5s ease-out;
+    -moz-transition: all 0.5s ease-out;
+    -webkit-transition: all 0.5s ease-out;
+    -o-transition: all 0.5s ease-out;
+    height: 100%;
+    object-fit: contain;
+}
+
+/* 防止 Vue 页面闪烁 */
+[v-cloak] {
+    display: none !important;
+}
+
+/* 设置滚动条 */
+html, body {
+    -ms-overflow-style: scrollbar;
+    background-color: var(--bodyBackground);
+}
+
+::-webkit-scrollbar {
+    width: 13px;
+    height: 13px;
+}
+
+::-webkit-scrollbar-thumb {
+    background-color: rgba(0, 0, 0, .4);
+    background-clip: padding-box;
+    border: 3px solid transparent;
+    border-radius: 7px;
+}
+
+::-webkit-scrollbar-track {
+    background-color: transparent;
+}
+
+/* 设置滚动条 end. */
+
+.page-container {
+    position: relative;
+    width: 100%;
+    height: 100%;
+}
+
+.layout {
+    height: 100%;
+}
+
+#app-main {
+    width: 100%;
+    height: 100%;
+    margin: 0 auto;
+    -webkit-transition: all .2s;
+    transition: all .2s;
+}
+
+.page-container .layout #app-main .page-left {
+    position: fixed;
+    z-index: 1010;
+    top: 0;
+    bottom: 0;
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: var(--real-sidebar-width);
+    transition: width 0.2s;
+    -webkit-box-shadow: 10px 0 10px -10px var(--leftBackground);
+    box-shadow: 10px 0 10px -10px var(--leftBackground);
+    background: var(--leftBackground);
+    color: #fff;
+    -webkit-transition: .3s;
+    transition: .3s;
+    overflow-x: hidden;
+    /*overflow-y: auto;*/
+    -ms-scroll-chaining: none;
+    overscroll-behavior: contain;
+    scrollbar-width: none;
+}
+
+.page-container .layout #app-main .page-left::-webkit-scrollbar {
+    display: none;
+}
+
+.page-container .layout #app-main .page-left .left-title {
+    position: fixed;
+    z-index: 1000;
+    top: 0;
+    width: inherit;
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    -webkit-box-pack: center;
+    -ms-flex-pack: center;
+    justify-content: center;
+    height: 50px;
+    text-align: center;
+    overflow: hidden;
+    text-decoration: none;
+    background: var(--leftBackground);
+    -webkit-transition: background .3s;
+    transition: background .3s;
+}
+
+.page-container .layout #app-main .page-left .left-title img {
+    width: 30px;
+    border-radius: 3px;
+}
+
+.page-container .layout #app-main .page-left .left-title span {
+    font-size: 14px;
+    font-weight: 700;
+    margin-left: 5px;
+}
+
+.el-menu-vertical-demo {
+    border-right: none;
+    padding-top: 50px;
+}
+
+.el-menu-vertical-demo::-webkit-scrollbar {
+    width: 0 !important
+}
+
+.page-container .layout #app-main .page-mask {
+    position: fixed;
+    z-index: 1000;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, .5);
+    -webkit-backdrop-filter: blur(2px);
+    backdrop-filter: blur(2px);
+    -webkit-transition: all .2s;
+    transition: all .2s;
+    -webkit-transform: translateZ(0);
+    transform: translateZ(0);
+    opacity: 0;
+    visibility: hidden;
+}
+
+.page-container .layout #app-main .page-main {
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+    min-height: 100%;
+    margin-left: var(--real-sidebar-width);
+    background-color: var(--bodyBackground);
+    -webkit-box-shadow: 1px 0 0 0 #d5dee6;
+    box-shadow: 1px 0 0 0 #d5dee6;
+    -webkit-transition: .3s;
+    transition: .3s;
+}
+
+.page-container .layout #app-main .page-main .main-header[data-7512a93d] {
+    position: fixed;
+    z-index: 999;
+    top: 0;
+    right: 0;
+    left: 50%;
+    width: calc(100% - var(--real-sidebar-width));
+    -webkit-transform: translateX(calc(-50% + var(--real-sidebar-width) * 0.5));
+    transform: translateX(calc(-50% + var(--real-sidebar-width) * 0.5));
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    -webkit-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    height: 50px;
+    background: var(--headerBackground);
+    color: var(--headerTextColors);
+    -webkit-transition: .3s, -webkit-box-shadow .2s;
+    transition: .3s, -webkit-box-shadow .2s;
+    transition: .3s, box-shadow .2s;
+    transition: .3s, box-shadow .2s, -webkit-box-shadow .2s;
+    -webkit-box-shadow: 0 0 1px 0 #ccc;
+    box-shadow: 0 0 1px 0 #ccc;
+}
+
+.page-container .layout #app-main .page-main .main-header .right-header .el-dropdown {
+    color: var(--headerTextColors);
+}
+
+.Va-aside-menu[data-7512a93d] {
+    -webkit-transition: .3s;
+    transition: .3s;
+    background: var(--leftBackground)
+}
+
+.Va-aside-menu[data-7512a93d] .el-menu-item {
+    color: var(--leftTextColors);
+    background: var(--leftBackground)
+}
+
+.Va-aside-menu[data-7512a93d] .el-menu-item.is-active {
+    color: var(--themeColors);
+    background: #409EFF23;
+    border-left: 3px solid var(--themeColors)
+}
+
+.Va-aside-menu[data-7512a93d] .el-submenu__title {
+    color: var(--leftTextColors);
+    background: var(--leftBackground);
+    font-size: 14px;
+}
+
+.Va-aside-menu[data-7512a93d] .va-children .el-submenu__title {
+    color: var(--leftTextColors);
+    background: var(--leftBackground);
+    font-size: 14px;
+}
+
+.el-menu-item i, .el-submenu__title i {
+    color: inherit;
+}
+
+.Va-aside-menu[data-7512a93d] .el-menu-item:hover, .Va-aside-menu[data-7512a93d] .el-submenu__title:hover {
+    color: var(--themeColors);
+    background: var(--leftBackground)
+}
+
+.Va-aside-menu[data-7512a93d] .el-menu {
+    background: var(--leftBackground);
+}
+
+.Va-aside-menu[data-7512a93d] .Va-aside-menu[data-7512a93d] .el-menu-item.is-active {
+    color: var(--themeColors);
+    background: var(--leftBackground)
+}
+
+.Va-aside-menu[data-7512a93d] .el-submenu.is-active .el-menu .el-menu-item.is-active {
+    color: var(--themeColors);
+    background: #ffffff;
+    border-left: 3px solid var(--themeColors)
+}
+
+.page-container .layout #app-main .page-main .main-header .right-header .functional-areas {
+    padding: 0px 20px;
+}
+
+.page-container .layout #app-main .page-main .main-header .right-header .functional-areas .theme .el-dropdown-link .svg-icon {
+    width: 20px;
+    height: 20px;
+}
+
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+    width: 200px;
+    max-height: 100vh;
+    min-height: 400px;
+}
+
+.page-container .layout #app-main .page-main .main-content {
+    /*height: 100%;*/
+    /*-webkit-box-flex: 1;*/
+    /*-ms-flex: auto;*/
+    /*flex: auto;*/
+    /*position: relative;*/
+    /*overflow: hidden;*/
+    margin: 60px 10px 10px 10px;
+    /*background: #f0f0f0;*/
+    border-radius: 3px;
+}
+
+.left-header {
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding-right: 50px;
+    overflow: hidden;
+    -webkit-mask-image: linear-gradient(90deg, #000, #000 calc(100% - 50px), transparent);
+    mask-image: linear-gradient(90deg, #000, #000 calc(100% - 50px), transparent);
+}
+
+.right-header {
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding: 0 17px;
+    white-space: nowrap;
+}
+
+.sidebar-collapse {
+    display: flex;
+    align-items: center;
+    padding: 0 20px;
+    height: 50px;
+    cursor: pointer;
+    transition: 0.3s;
+}
+
+.sidebar-collapse:hover {
+    background-image: linear-gradient(to right, #ddd, transparent);
+}
+
+.svg-icon {
+    transition: 0.3s;
+}
+
+.is-collapse .svg-icon {
+    transform: rotateZ(-180deg);
+}
+
+.el-breadcrumb {
+    margin-left: 0;
+}
+
+.head-image {
+    width: 30px;
+    border-radius: 3px;
+    vertical-align: middle;
+    margin-top: -2px;
+    margin-right: 4px;
+    /*box-shadow: 0 0 1px 1px var(--leftBackground);*/
+}
+
+.form-container {
+    background: #fff;
+    padding: 20px;
+}
+
+.form-container-header .options-right {
+    float: right;
+    display: inline-block;
+    margin-bottom: 10px;
+}
+
+#nprogress .bar {
+    background: var(--themeColors);
+!important;
+}
+
+.has-gutter tr th {
+    background: #f5f6fa;
+}
+
+.inline-tables .el-table .cell {
+    white-space: nowrap;
+    font-size: 12px;
+    min-height: 36px;
+    line-height: 36px;
+}
+
+.inline-tables .el-table td {
+    padding: 0 0
+}
+
+.inline-tables .el-table th {
+    padding: 1px 0
+}
+
+.Va-table-move {
+    position: relative;
+    white-space: pre-wrap !important;
+    width: max-content !important;
+    background: #fff;
+    text-align: left;
+    z-index: 1991;
+    padding: 0 10px !important;
+    border-radius: 4px;
+    max-width: 400px;
+    word-break: break-all !important;
+    font-size: 14px;
+    overflow: visible !important;
+    text-overflow: clip !important;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)
+}
+
+.Va-table-move-close {
+    top: -10px;
+    right: -10px;
+    position: absolute;
+    width: 20px;
+    height: 20px;
+    padding: 0 0 0 0.5px;
+    cursor: pointer;
+    background-color: #666;
+    border-radius: 50%;
+    color: #fff;
+    z-index: 9999999999;
+    margin: 0 auto;
+    font-size: 20px;
+}
+.Va-container-tables-pagination-box{
+    text-align: right;margin-top: 10px;
+}
+.Va-container[data-7512a93d] .Va-container-tables-pagination[data-7512a93d] {
+    text-align: right;
+    margin-bottom: 10px;
+    margin-top: 10px
+}
+
+.el-button[inline] {
+    padding: 4PX 5PX;
+    margin-left: 5px;
+}
+
+.Va-drawer.fixed {
+    position: fixed;
+    right: 0;
+    border-radius: 0;
+    margin-top: 0 !important;
+    margin-bottom: 0 !important;
+    height: -webkit-fill-available;
+}
+
+.Va-drawer .el-drawer__header {
+    border-bottom: 1px solid #eee;
+    padding: 15px 20px 10px;
+    margin-bottom: 0;
+}
+
+.el-drawer__header > :first-child {
+    font-size: 18px;
+}
+
+.Va-drawer.fixed .Va-drawer-main[data-7512a93d] {
+    overflow: auto;
+}
+
+.Va-drawer.fixed .el-drawer__body {
+    padding: 1px 12px 1px 15px;
+}
+
+.Va-drawer .el-drawer__body {
+    padding: 1px 12px 1px 5px;
+    min-height: 200px;
+}
+
+.el-drawer__body {
+    padding: 10px 22px;
+    min-height: 200px;
+}
+
+.Va-drawer .Va-forms[data-7512a93d] {
+    padding: 15px;
+}
+
+.Va-forms[data-7512a93d].el-form--label-top .el-form-item {
+    margin-bottom: 15px;
+}
+
+.Va-forms[data-7512a93d].el-form--label-top .el-form-item__label {
+    padding: 0 0 1px;
+    line-height: 20px;
+}
+
+.Va-forms[data-7512a93d] .el-form-item__label {
+    word-wrap: break-word;
+    word-break: normal;
+}
+
+/*footer*/
+.el-drawer__footer {
+    padding: 5px 20px 8px;
+}
+
+.el-drawer__footer {
+    padding: 10px 20px 20px;
+    text-align: right;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+}
+
+.Va-drawer .Va-drawer-footer[data-7512a93d] {
+    border-top: 1px solid #eee;
+    padding-top: 10px;
+    padding-bottom: 5px;
+}
+
+/*footer*/
+.Va-text-left[data-7512a93d] {
+    text-align: left;
+}
+
+.Va-dialog.fixed .el-dialog__body {
+    padding: 1px 12px 1px 15px
+}
+
+.Va-dialog.fixed .Va-dialog-main[data-7512a93d] {
+    overflow: auto
+}
+
+.Va-dialog.auto .Va-dialog-main[data-7512a93d] {
+    overflow: auto
+}
+
+.Va-dialog.auto .el-card__body {
+    padding: 8px
+}
+
+.Va-dialog .el-dialog__header {
+    border-bottom: 1px solid #eee;
+    padding: 15px 20px 10px
+}
+
+.Va-dialog .Va-dialog-footer[data-7512a93d] {
+    border-top: 1px solid #eee;
+    padding-top: 10px;
+    padding-bottom: 5px
+}
+
+[class*=" el-icon-"], [class^=el-icon-] {
+    font-family: element-icons !important;
+    speak: none;
+    font-style: normal;
+    font-weight: 400;
+    font-variant: normal;
+    text-transform: none;
+    line-height: 1;
+    vertical-align: baseline;
+    display: inline-block;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+}
+
+/* 字体色 */
+.Va-help-block.success, .table-span.success, .views-span.success {
+    color: #67C23A
+}
+
+.Va-help-block.warning, .table-span.warning, .views-span.warning {
+    color: #E6A23C
+}
+
+.Va-help-block.fail, .table-span.fail, .views-span.fail {
+    color: #F56C6C
+}
+
+.Va-help-block.primary, .table-span.primary, .views-span.primary {
+    color: #409EFF
+}
+
+.Va-help-block.black, .table-span.black, .views-span.black {
+    color: #344058
+}
+
+.Va-help-block.purple, .table-span.purple, .views-span.purple {
+    color: #d21074
+}
+
+.Va-help-block.blue, .table-span.blue, .views-span.blue {
+    color: #2d6973
+}
+
+.va-el-dropdown-link {
+    font-size: 12px;
+    color: var(--themeColors);
+}
+
+.el-button[primary] {
+    color: var(--themeColors)
+}
+
+.el-button[primary]:hover {
+    color: var(--buttonHoverColors)
+}
+
+.el-button[primary].is-disabled {
+    color: #a0cfff
+}
+
+.el-button[success] {
+    color: #67c23a
+}
+
+.el-button[success]:hover {
+    color: #85ce61
+}
+
+.el-button[success].is-disabled {
+    color: #b3e19d
+}
+
+.el-button[info] {
+    color: #909399
+}
+
+.el-button[info]:hover {
+    color: #a6a9ad
+}
+
+.el-button[info].is-disabled {
+    color: #c8c9cc
+}
+
+.el-button[warning] {
+    color: #e6a23c
+}
+
+.el-button[warning]:hover {
+    color: #ebb563
+}
+
+.el-button[warning].is-disabled {
+    color: #f3d19e
+}
+
+.el-button[danger] {
+    color: #F56C6C
+}
+
+.el-button[danger]:hover {
+    color: #f78989
+}
+
+.el-button[danger].is-disabled {
+    color: #fab6b6
+}
+
+.Va-help-block {
+    display: block;
+    margin-top: 3px;
+    color: #737373;
+    font-size: 12px;
+    min-height: 18px;
+    margin-bottom: 0;
+    line-height: 1.5
+}
+
+.Va-help-block:hover {
+    color: #222
+}
+
+.Va-dialog .Va-dialog-footer[data-7512a93d] {
+    border-top: 1px solid #eee;
+    padding-top: 10px;
+    padding-bottom: 5px
+}
+
+.Va-text-right[data-7512a93d] {
+    text-align: right
+}
+
+.Va-text-left[data-7512a93d] {
+    text-align: left
+}
+
+.forms-items-left {
+    float: left;
+    width: 49%;
+    overflow: hidden;
+}
+
+.forms-items-right {
+    float: right;
+    width: 49%;
+    overflow: hidden;
+}
+
+.float-clear {
+    clear: both
+}
+
+.forms-divider {
+    width: 100%;
+    margin-bottom: 12px;
+    font-weight: 500
+}
+
+.forms-divider.line {
+    border-bottom: 2px solid rgba(0, 0, 0, 0.1);
+    box-shadow: 0 2px 0 -5px rgba(0, 0, 0, 0.1);
+}
+
+.forms-divider > .left {
+    font-size: 20px;
+    padding-left: 10px;
+    color: #333;
+    font-weight: 600;
+}
+
+.forms-divider > .right {
+    font-size: 20px;
+    /*padding-right: 10px;*/
+    float: right;
+    padding-bottom: 5px;
+    color: #333;
+    font-weight: 600;
+}
+
+.va-component-picture {
+    position: relative;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 108px;
+    height: 108px;
+    line-height: 106px;
+    vertical-align: top;
+    overflow: hidden;
+    display: inline-block
+}
+
+.va-component-picture:hover {
+    border: 1px dashed var(--themeColors);
+}
+
+.va-component-picture .upload {
+    position: relative;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 108px;
+    height: 108px;
+    line-height: 106px;
+    vertical-align: top
+}
+
+.va-component-picture .upload .icon {
+    font-size: 50px;
+    margin-top: 25px;
+    text-align: center;
+    cursor: pointer;
+    display: block;
+    color: #8c939d
+}
+
+.va-component-picture.iconfont {
+    position: relative;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 85px;
+    height: 85px;
+    line-height: 80px;
+    vertical-align: top;
+    overflow: hidden;
+    display: inline-block
+}
+
+.va-component-picture.iconfont .upload {
+    position: relative;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 85px;
+    height: 85px;
+    line-height: 80px;
+    vertical-align: top
+}
+
+.va-component-picture.iconfont .upload:hover .upload-block {
+    display: inline-block;
+}
+
+.va-component-picture.iconfont .upload-block {
+    display: inline-block;
+    position: absolute;
+    border-radius: 2px;
+    box-sizing: border-box;
+    width: 82px;
+    height: 27px;
+    background: #000;
+    bottom: -1px;
+    opacity: .4;
+}
+
+.va-component-picture.iconfont .upload-block-icon {
+    display: inline-block;
+    position: absolute;
+    box-sizing: border-box;
+    width: 82px;
+    height: 27px;
+    line-height: 27px;
+    text-align: center;
+    bottom: -1px;
+    color: var(--themeColors);
+}
+
+.va-component-picture.iconfont .upload .icon, .va-component-picture.iconfont .upload .fa {
+    font-size: 55px;
+    margin-top: 10px;
+    text-align: center;
+    cursor: pointer;
+    display: block;
+    color: #8c939d
+}
+
+.va-component-picture.iconfont .upload .iconfont {
+    font-size: 55px;
+    text-align: center;
+    cursor: pointer;
+    display: block;
+    color: #8c939d
+}
+
+.va-component-picture .show {
+    position: relative;
+    background-color: #fbfdff;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 108px;
+    height: 108px;
+    line-height: 106px;
+    vertical-align: top
+}
+
+.va-component-picture .show .image {
+    width: 104px;
+    height: 105px;
+    object-fit: contain;
+    border-radius: 6px;
+    position: absolute;
+    left: 0;
+    top: 0;
+    transition: all 0.5s ease-out;
+    -moz-transition: all 0.5s ease-out;
+    -webkit-transition: all 0.5s ease-out;
+    -o-transition: all 0.5s ease-out
+}
+
+.va-component-picture .show .shadow {
+    position: absolute;
+    width: 100%;
+    height: 30px;
+    left: 0;
+    bottom: 0;
+    text-align: center;
+    color: #fff;
+    font-size: 20px;
+    background-color: rgba(0, 0, 0, .5);
+    -webkit-transition: opacity .3s;
+    transition: opacity .3s
+}
+
+.va-component-picture .show .shadow .icon {
+    color: rgb(254, 254, 254);
+    font-size: 16px;
+    cursor: pointer;
+    margin-top: 5px;
+    float: left;
+    margin-left: 10px
+}
+
+.va-component-picture .show .shadow .icon.float-right {
+    float: right !important;
+    margin-right: 15px
+}
+
+.va-component-picture .show:hover .image {
+    transform: scale(1.2, 1.2)
+}
+
+.va-component-picture .el-progress-circle {
+    width: 90px !important;
+    height: 90px !important;
+}
+
+.el-dialog__body {
+    padding: 10px 22px;
+    min-height: 200px
+}
+
+.Va-dialog .el-dialog__body {
+    padding: 1px 12px 1px 5px;
+    min-height: 200px
+}
+
+.Va-dialog .Va-forms[data-7512a93d] {
+    padding: 15px
+}
+
+.el-dialog__footer {
+    padding: 5px 20px 8px
+}
+
+.gallery-tab .el-tabs__header {
+    margin-bottom: 0
+}
+
+.gallery-tab .el-tabs__header .el-tabs__nav {
+    margin-left: 30px
+}
+
+.gallery-group {
+    height: 90%
+}
+
+.gallery-group-create {
+    display: inline-block;
+    text-align: right;
+    position: absolute;
+    bottom: 9px
+}
+
+.Va-forms .el-upload {
+    display: inline-flex
+}
+
+.Va-picture:hover .el-image__inner {
+    transform: scale(1.2, 1.2)
+}
+
+.el-image__inner {
+    transition: all 0.5s ease-out;
+    -moz-transition: all 0.5s ease-out;
+    -webkit-transition: all 0.5s ease-out;
+    -o-transition: all 0.5s ease-out;
+    border-radius: 5px
+}
+
+.Va-picture {
+    margin-top: 30px;
+    position: relative;
+    width: 200px;
+    height: 235px;
+    line-height: 225px
+}
+
+.Va-picture-image {
+    width: 100%;
+    height: inherit;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+    background: #fbfdff
+}
+
+.Va-picture-image .default {
+    font-size: 48px;
+    color: #8c939d;
+    display: block;
+    text-align: center;
+    line-height: inherit
+}
+
+.Va-picture-shadow {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    left: 1px;
+    top: 1px;
+    cursor: pointer;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    font-size: 20px;
+    background-color: rgba(0, 0, 0, .5);
+    -webkit-transition: opacity .3s;
+    transition: opacity .3s;
+    border-radius: 5px
+}
+
+.Va-picture:hover .Va-picture-shadow {
+    opacity: .9
+}
+
+.Va-picture-shadow .options {
+    font-size: 22px;
+    display: contents;
+    text-align: center;
+    color: white
+}
+
+.va-component-file {
+    background-color: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 300px;
+    height: 145px;
+    text-align: center;
+    position: relative;
+    overflow: hidden
+}
+
+.va-component-file .files {
+    background-color: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 320px;
+    height: 160px;
+    text-align: center;
+    position: relative;
+    overflow: hidden;
+    margin-bottom: 10px
+}
+
+.va-component-file .el-upload-dragger {
+    width: 300px;
+    border: none
+}
+
+.va-component-file .progress {
+    margin: 0 auto;
+    position: relative;
+    top: 12%
+}
+
+.va-component-file .files .button {
+    position: absolute;
+    right: 30px;
+    top: 12px
+}
+
+.va-component-file:hover {
+    border-color: var(--themeColors)
+}
+
+.va-component-file .upload:hover {
+    cursor: pointer
+}
+
+.va-component-file .upload .icon, .va-component-file .files .icon {
+    font-size: 50px;
+    color: #C0C4CC;
+    margin: 20px 0 0;
+    line-height: 40px
+}
+
+.va-component-file .files .icon {
+    margin-top: 25px
+}
+
+.va-component-file[disabled] {
+    background-color: #F5F7FA !important;
+    border-color: #E4E7ED;
+    color: #C0C4CC;
+    cursor: not-allowed
+}
+
+.va-component-file[disabled] .upload {
+    background-color: #F5F7FA !important;
+    border-color: #E4E7ED;
+    color: #C0C4CC;
+    cursor: not-allowed;
+    height: 100%;
+}
+
+.va-component-file[disabled] .icon {
+    cursor: not-allowed !important
+}
+
+.va-gallery-main {
+    position: relative;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 148px;
+    height: 148px;
+    line-height: 146px;
+    vertical-align: top;
+    overflow: hidden
+}
+
+.va-gallery-multiple {
+    clear: both;
+    display: flex
+}
+
+.va-gallery-multiple .va-gallery-main {
+    float: left;
+    margin-left: 8px
+}
+
+.va-gallery-upload {
+    position: relative;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 148px;
+    height: 148px;
+    line-height: 146px;
+    vertical-align: top
+}
+
+.gallery-upload-tips {
+    margin-right: 10px;
+    margin-top: 5px;
+    display: inline-block;
+}
+
+.va-gallery-upload .va-gallery-icon {
+    font-size: 50px;
+    margin-top: 40px;
+    text-align: center;
+    cursor: pointer;
+    display: block;
+    color: #8c939d
+}
+
+.va-gallery-upload .va-gallery-icon:hover {
+    cursor: pointer
+}
+
+.va-gallery-image {
+    width: 100%;
+    height: 100%
+}
+
+.va-gallery-image .image {
+    width: 144px;
+    height: 145px;
+    object-fit: contain;
+    border-radius: 6px;
+    position: absolute;
+    left: 0;
+    top: 0;
+    transition: all 0.5s ease-out;
+    -moz-transition: all 0.5s ease-out;
+    -webkit-transition: all 0.5s ease-out;
+    -o-transition: all 0.5s ease-out
+}
+
+.va-gallery-shadow {
+    position: absolute;
+    width: 100%;
+    height: 30px;
+    left: 0;
+    bottom: 0;
+    text-align: center;
+    color: #fff;
+    font-size: 20px;
+    background-color: rgba(0, 0, 0, .5);
+    -webkit-transition: opacity .3s;
+    transition: opacity .3s
+}
+
+.va-gallery-shadow .va-gallery-icon {
+    color: rgb(254, 254, 254);
+    font-size: 20px;
+    cursor: pointer;
+    margin-top: 6px;
+    float: left;
+    margin-left: 15px
+}
+
+.va-gallery-shadow .va-gallery-icon.float-right {
+    float: right !important;
+    margin-right: 15px
+}
+
+.va-gallery-image:hover .image {
+    transform: scale(1.2, 1.2)
+}
+
+.va-gallery-image:hover .va-gallery-shadow {
+    opacity: .8
+}
+
+.va-gallery-upload.gallery:hover {
+    cursor: pointer
+}
+
+.__gallery_group {
+    width: 100%;
+    display: block;
+    margin-bottom: 15px;
+    height: 30px;
+    margin-left: 10px
+}
+
+.__gallery_group_item {
+    cursor: pointer;
+    min-width: 10px;
+    height: 30px;
+    border-radius: 15px;
+    -moz-border-radius: 15px;
+    -webkit-border-radius: 15px;
+    margin-right: 10px;
+    display: inline-block;
+    float: left;
+    padding: 0 8px;
+    line-height: 30px;
+    border: 1px solid transparent;
+}
+
+.__gallery_group_item.is_active {
+    color: var(--themeColors);
+    border-color: currentColor;
+}
+
+.__gallery_group_item:hover {
+    color: var(--themeColors);
+    border-color: currentColor;
+}
+
+.__gallery_group_item_update {
+    cursor: pointer;
+    min-width: 10px;
+    height: 30px;
+    border-radius: 5px;
+    margin-right: 10px;
+    display: inline-block;
+    float: left;
+    padding: 0 8px;
+    line-height: 30px;
+    border: 1px solid transparent;
+}
+
+.__gallery_group_item_update:hover {
+    color: var(--themeColors);
+}
+
+.gallery-header {
+    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+    min-height: 90px;
+}
+
+.gallery-dialog-group-box {
+    margin-top: 10px;
+    clear: both;
+    padding-left: 8px;
+}
+
+.gallery-dialog-group-box .item {
+    min-width: 85px;
+    display: inline-block;
+    text-align: center;
+    padding: 4px 12px;
+    margin-right: 12px;
+    border: 1px solid var(--themeColors);
+    border-radius: 20px;
+    margin-bottom: 8px;
+}
+
+.gallery-dialog-group-box .item:hover {
+    cursor: pointer;
+    background: var(--themeColors);
+    color: white;
+    border: 1px solid white;
+}
+
+.gallery-dialog-group-box .item.active {
+    cursor: pointer;
+    background: var(--themeColors);
+    color: white;
+    border: 1px solid white;
+}
+
+.gallery-dialog-image-item {
+    float: left;
+    width: 15.4%;
+    height: 200px;
+    padding: 10px 5px 0 5px;
+    position: relative;
+    overflow: hidden
+}
+
+.gallery-dialog-image-item.index {
+    float: left;
+    width: 12.5%;
+    padding: 8px;
+    position: relative;
+    overflow: hidden
+}
+
+.gallery-dialog-image-item:hover {
+    cursor: pointer;
+}
+
+.gallery-dialog-image-item .el-image {
+    border-radius: 5px;
+    border: 1px dashed #d9d9d9;
+    height: 140px;
+    width: 100%
+}
+
+.gallery-dialog-image-item .el-image:hover {
+    border: 1px dashed var(--themeColors);
+}
+
+.gallery-dialog-image-item .el-image .image-slot, .gallery-dialog-image-item .el-image .image-slot .iconfont {
+    text-align: center;
+    margin-top: 20%;
+    font-size: 50px;
+}
+
+.gallery-dialog-image-item:hover .el-image__inner {
+    transform: scale(1.2, 1.2)
+}
+
+.gallery-image-dropdown {
+    position: absolute;
+    right: 17px;
+    top: 17px;
+    z-index: 10;
+}
+
+.gallery-image-checkbox {
+    position: absolute;
+    left: 20px;
+    top: 18px;
+    font-size: 25px;
+    color: #EBEEF5;
+    z-index: 10;
+}
+
+.gallery-image-active {
+    position: absolute;
+    left: 20px;
+    top: 18px;
+    font-size: 25px;
+    color: #07C160;
+    z-index: 10;
+}
+
+.gallery-image-dropdown:hover, .gallery-image-checkbox:hover, .gallery-image-active:hover {
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] {
+    width: 140px;
+    height: 145px;
+    background: white;
+    padding: 10px;
+    margin: 10px;
+    float: left;
+    border-radius: 5px;
+    position: relative;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04)
+}
+
+.Va-imageDialog-item[data-7512a93d]:hover .Va-imageDialog-mask, .Va-imageDialog-item[data-7512a93d]:hover .Va-imageDialog-checkbox {
+    display: inline-block
+}
+
+.Va-imageDialog-item[data-7512a93d] .Va-imageDialog-mask {
+    width: 100%;
+    height: 100%;
+    background: #111;
+    opacity: 0.1;
+    position: absolute;
+    z-index: 10;
+    border-radius: 5px;
+    display: none;
+    top: 0;
+    left: 0;
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] .Va-imageDialog-checkbox {
+    width: 140px;
+    height: 145px;
+    position: absolute;
+    z-index: 20;
+    display: none;
+    left: 50px;
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] .Va-imageDialog-container[data-7512a93d] {
+    height: 120px;
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] .Va-imageDialog-container[data-7512a93d] .el-image {
+    width: 140px;
+    margin: 0 auto;
+    height: 100%;
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] .Va-imageDialog-container[data-7512a93d] .title {
+    width: 140px;
+    padding-left: 5px;
+    font-size: 14px;
+    display: inline-block;
+    height: 20px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    cursor: pointer
+}
+
+.Va-imageDialog-item[data-7512a93d] .itemsChecked {
+    display: inline-block
+}
+
+.Va-imageDialog-container[data-7512a93d] .image-slot {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    color: #aaa;
+    font-size: 26px
+}
+
+.Va-image-multiple[data-7512a93d] {
+    width: 100%
+}
+
+.Va-image-multiple[data-7512a93d] .el-image {
+    width: 88px;
+    height: 88px;
+    border: 1px dashed #bbbbbb;
+    border-radius: 3px;
+    cursor: pointer
+}
+
+.Va-image-multiple[data-7512a93d] .Va-image-multiple-update[data-7512a93d] {
+    display: inline-block
+}
+
+.Va-image-multiple[data-7512a93d] .Va-image-multiple-box[data-7512a93d] {
+    display: inline-block
+}
+
+.Va-image-multiple[data-7512a93d] .Va-image-multiple-box[data-7512a93d] .el-image {
+    margin-right: 10px
+}
+
+.Va-image-multiple[data-7512a93d] .image-slot {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background: #f5f7fa;
+    color: #aaa;
+    font-size: 26px
+}
+
+.Va-image-box[data-7512a93d] {
+    width: 100px;
+    float: left
+}
+
+.Va-image-box[data-7512a93d] .el-image {
+    width: 88px;
+    height: 88px;
+    border: 1px dashed #bbbbbb;
+    border-radius: 3px;
+    cursor: pointer
+}
+
+.Va-image-box[data-7512a93d] .image-slot {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background: #f5f7fa;
+    color: #aaa;
+    font-size: 26px
+}
+
+.tables-image {
+    padding-top: 5px;
+    height: 40px;
+    width: 55px
+}
+
+.transform-image {
+    overflow: hidden;
+    transition: all 0.5s ease-out;
+}
+
+.forms-upload-box:hover img, .tables-image:hover img, .el-image:hover img, .transform-image img:hover {
+    transform: scale(1.2, 1.2);
+}
+
+.select-line-left{
+    float: left
+}
+
+.select-line-right{
+    float: right;
+    color: #8492a6;
+    font-size: 13px
+}
+
+.No-data {
+    text-align: center;
+    line-height: 20;
+    font-size: 16px;
+    color: #9a9a9a
+}
+
+.text-space {
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    word-break: break-all;
+    display: inline-block;
+    width: 100%
+}
+
+.setup-file-compress {
+    width: 150px;
+}
+
+.setup-file-compress label {
+    width: 100%;
+    text-align: center;
+}
+
+.setup-file-compress label {
+    width: 50px;
+    display: block;
+    background-color: var(--leftBackground);
+    box-sizing: border-box;
+    position: relative;
+    cursor: pointer;
+    float: left;
+    height: 42px;
+    border: 1px solid #e6e9f0;
+    margin: 0;
+    color: #8d9199;
+    text-align: center;
+    line-height: 42px;
+}
+
+.setup-file-compress label:nth-child(1) {
+    border-radius: 5px 0 0 0
+}
+
+.setup-file-compress label:nth-child(3) {
+    border-radius: 0 5px 0 0
+}
+
+.setup-file-compress label:nth-child(7) {
+    border-radius: 0 0 0 5px
+}
+
+.setup-file-compress label:nth-child(9) {
+    border-radius: 0 0 5px 0
+}
+
+.setup-file-compress label:hover {
+    background-color: var(--themeColors);
+    color: white
+}
+
+.setup-file-compress .active {
+    background-color: var(--themeColors);
+    color: white
+}
+
+/* tinymce 与 element 抽屉弹出层冲突 */
+.tox-tinymce-aux {
+    z-index: 9999 !important;
+}
+
+.tinymce.ui.FloatPanel {
+    z-Index: 99 !important;
+}
+
+@media screen and (max-width: 500px){
+    .page-container .layout #app-main .page-main .main-header .right-header .functional-areas{
+        padding: 0;
+    }
+    .right-header{
+        padding: 0 8px;
+    }
+}
+
+/* 控制台风格 */
+.home{
+    overflow: hidden;
+    background-color: var(--headerBackground);
+    color: var(--headerTextColors);
+}
+/* 控制台风格 end */
+
+/* 主题色 */
+:root {
+    --themeColors: #009688;
+    --themeTextColors: #F9F9F9;
+    --themeSelectColors: #606266;
+    --headerBackground: #fff;
+    --headerTextColors: #303133;
+    --leftBackground: #344058;
+    --leftTextColors: #fff;
+    --buttonHoverColors: #009688;
+    --bodyBackground: #f0f2f5;
+}

+ 4915 - 0
public/assets/v1/app.js

@@ -0,0 +1,4915 @@
+window.$Request = {
+    post: function (url, data, response, type) {
+        NProgress.start();
+        $Request.httpRequest({
+            url: url,
+            data: data ? data : {},
+            type: type ? type : 'POST',
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
+                'X-CSRF-TOKEN': ($('meta[name="csrf-token"]').attr('content') ? $('meta[name="csrf-token"]').attr('content') : $(window.parent.document).find('meta[name="csrf-token"]').attr('content'))
+            },
+            response: function (res, status, header) {
+                // console.log(status);
+                /*错误码 400*/
+                if (status > 399 && status < 500) {
+                    NProgress.done();
+                    $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                    // window.location = '/404?msg=页面未找到';
+                    return false;
+                }
+                /*错误码 500*/
+                else if (status >= 500) {
+                    NProgress.done();
+                    $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                    return false;
+                } else {
+                    if (!res) {
+                        NProgress.done();
+                        $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                        return false;
+                    }
+                    NProgress.done();
+                    response(res);
+                }
+            }
+        })
+    },
+
+    postJson: function (url, data, response, type) {
+        var platform = $('meta[name="framework-platform"]').attr('content');
+        NProgress.start();
+        $Request.httpJsonRequest({
+            url: url,
+            data: data ? data : {},
+            type: type ? type : 'POST',
+            headers: {
+                'Request-Source' :platform,
+                'Content-Type': 'application/json; charset=UTF-8',
+                'X-CSRF-TOKEN': ($('meta[name="csrf-token"]').attr('content') ? $('meta[name="csrf-token"]').attr('content') : $(window.parent.document).find('meta[name="csrf-token"]').attr('content'))
+            },
+            response: function (res, status, header) {
+                // console.log(status);
+                /*错误码 400*/
+                if (status > 399 && status < 500) {
+                    NProgress.done();
+                    $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                    // window.location = '/404?msg=页面未找到';
+                    return false;
+                }
+                /*错误码 500*/
+                else if (status >= 500) {
+                    NProgress.done();
+                    $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                    return false;
+                } else {
+                    if (!res) {
+                        NProgress.done();
+                        $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                        return false;
+                    }
+                    NProgress.done();
+                    response(res);
+                }
+            }
+        })
+    },
+
+    get: function (url, data) {
+        url = url ? url : window.location.href;
+
+        data = data ? data : {};
+
+        if ($.isEmptyObject(data)) {
+            window.location.href = url;
+        } else {
+            window.location.href = url + '?' + $Request.getQueryString(data);
+        }
+    },
+
+    open: function (url, data) {
+        url = url ? url : window.location.href;
+        data = data ? data : {};
+        if ($.isEmptyObject(data)) {
+            window.open(url);
+        } else {
+            window.open(url + '?' + $Request.getQueryString(data));
+        }
+    },
+
+    frame: function (url, data, options) {
+        if (!$.isEmptyObject(data)) {
+            url = url + '?' + $Request.getQueryString(data)
+        }
+        var _s = Object.assign({
+            width: (parseInt((document.documentElement.clientWidth / 100) * 55)) + 'px',
+            height: (parseInt((document.documentElement.clientHeight / 100) * 77)) + 'px',
+            msg: '正在打开页面,请稍后。。。'
+        }, options);
+
+        var iframe = document.createElement("iframe");
+        iframe.id = $Request.random(12);
+        iframe.src = url;
+        iframe.width = _s.width;
+        iframe.height = _s.height;
+        iframe.className = 'va-frame__wrapper_iframe';
+
+        $(".va-frame__wrapper").find('iframe').remove();
+        window.$__frameLoading = $App.$loading({
+            lock: true,
+            text: _s.msg,
+            spinner: 'el-icon-loading',
+        });
+
+        $(".va-frame__wrapper").append(iframe);
+
+        $(window).resize(function () {
+            $("body").find('.va-frame__wrapper_iframe').attr('width', (parseInt((document.documentElement.clientWidth / 100) * 55)) + 'px');
+            $("body").find('.va-frame__wrapper_iframe').attr('height', (parseInt((document.documentElement.clientHeight / 100) * 77)) + 'px');
+        });
+    },
+
+    href: function (url, data) {
+        url = url ? url : window.location.href;
+        data = data ? data : {};
+        if ($.isEmptyObject(data)) {
+            return url;
+        } else {
+            return url + '?' + $Request.getQueryString(data);
+        }
+    },
+
+    load: function (url, data, callback) {
+        var stateObject = {};
+        url = url ? url : window.location.href;
+        data = data ? data : {};
+        if (!$.isEmptyObject(data)) {
+            url = url + '?' + $Request.getQueryString(data);
+        }
+        $("#app").load(url, null, function (response, status, xhr) {
+            if (xhr.status === 404) {
+                $App.layouts.loading = false;
+                $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+                if (typeof callback === 'function') {
+                    callback(xhr.status);
+                }
+            } else if (xhr.status === 500) {
+                $App.layouts.loading = false;
+                $App.$message({message: '服务器响应错误,请稍后再试!', type: 'error'});
+                if (typeof callback === 'function') {
+                    callback(xhr.status);
+                }
+            } else {
+                history.pushState(stateObject, '', url);
+                if (typeof callback === 'function') {
+                    callback(xhr.status);
+                }
+                $App.layouts.loading = false;
+            }
+        });
+    },
+
+    random: function (length) {
+        length = length ? length : 16;
+        var result = '';
+        for (var i = 0; i < length; i++) {
+            result += Math.floor(Math.random() * 16).toString(16);
+        }
+        return result.toUpperCase();
+    },
+
+    httpRequest: function (settings) {
+        var _s = Object.assign({
+            url: window.location.href,
+            type: 'POST',
+            dataType: 'json',
+            async: true,
+            data: null,
+            headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
+            timeout: 0,
+            encrypt: true,
+            beforeSend: function (xhr) {
+
+            },
+            success: function (result, status, xhr) {
+
+            },
+            error: function (xhr, status, error) {
+                $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+            },
+
+            response: function (xhr, status) {
+
+            }
+        }, settings);
+        if (!_s.url) {
+            _s.url = window.location.href
+        }
+        // 参数验证
+        if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
+            $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+            return;
+        }
+        // 创建XMLHttpRequest请求对象
+        var xhr = new XMLHttpRequest();
+
+        // 请求开始回调函数
+        xhr.addEventListener('loadstart', function (e) {
+            _s.beforeSend(xhr);
+        });
+
+        // 请求成功回调函数
+        xhr.addEventListener('load', function (e) {
+            var status = xhr.status;
+            if ((status >= 200 && status < 300) || status === 304) {
+                var result;
+                if (xhr.responseType === 'text') {
+                    result = xhr.responseText;
+                } else if (xhr.responseType === 'document') {
+                    result = xhr.responseXML;
+                } else {
+                    result = xhr.response;
+                }
+                _s.success(result, status, xhr);
+            } else {
+                _s.error(xhr, status, e);
+            }
+        });
+
+        // 请求结束
+        xhr.addEventListener('loadend', function (e) {
+            var result;
+            if (xhr.responseType === 'text') {
+                result = xhr.responseText;
+            } else if (xhr.responseType === 'document') {
+                result = xhr.responseXML;
+            } else {
+                result = xhr.response;
+            }
+            _s.response(result, xhr.status);
+        });
+
+        // 请求出错
+        xhr.addEventListener('error', function (e) {
+            _s.error(xhr, xhr.status, e);
+        });
+
+        // 请求超时
+        xhr.addEventListener('timeout', function (e) {
+            _s.error(xhr, 408, e);
+        });
+
+        var useUrlParam = false;
+        var sType = _s.type.toUpperCase();
+        if (sType === 'GET' || sType === 'DELETE') {
+            useUrlParam = true;
+            _s.url += $Request.getUrlParam(_s.url, _s.data);
+        }
+        xhr.open(_s.type, _s.url, _s.async);
+        xhr.responseType = _s.dataType;
+        var headers_keys = Object.keys(_s.headers);
+        // 设置请求头
+        headers_keys.forEach(function (value, index, array) {
+            xhr.setRequestHeader(value, _s.headers[value]);
+        });
+        if (_s.async && _s.timeout) {
+            xhr.timeout = _s.timeout;
+        }
+
+        xhr.send(useUrlParam ? null : $Request.getQueryData(_s.data));
+    },
+
+    httpJsonRequest: function (settings) {
+        var _s = Object.assign({
+            url: window.location.href,
+            type: 'POST',
+            dataType: 'json',
+            async: true,
+            data: null,
+            headers: {'Content-Type': 'application/json; charset=UTF-8'},
+            timeout: 0,
+            encrypt: true,
+            beforeSend: function (xhr) {
+
+            },
+            success: function (result, status, xhr) {
+
+            },
+            error: function (xhr, status, error) {
+                $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+            },
+
+            response: function (xhr, status) {
+
+            }
+        }, settings);
+        if (!_s.url) {
+            _s.url = window.location.href
+        }
+        // 参数验证
+        if (!_s.url || !_s.type || !_s.dataType || !_s.async) {
+            $App.$message({message: '网络请求异常,请稍后再试!', type: 'error'});
+            return;
+        }
+        // 创建XMLHttpRequest请求对象
+        var xhr = new XMLHttpRequest();
+
+        // 请求开始回调函数
+        xhr.addEventListener('loadstart', function (e) {
+            _s.beforeSend(xhr);
+        });
+
+        // 请求成功回调函数
+        xhr.addEventListener('load', function (e) {
+            var status = xhr.status;
+            if ((status >= 200 && status < 300) || status === 304) {
+                var result;
+                if (xhr.responseType === 'text') {
+                    result = xhr.responseText;
+                } else if (xhr.responseType === 'document') {
+                    result = xhr.responseXML;
+                } else {
+                    result = xhr.response;
+                }
+                _s.success(result, status, xhr);
+            } else {
+                _s.error(xhr, status, e);
+            }
+        });
+
+        // 请求结束
+        xhr.addEventListener('loadend', function (e) {
+            var result;
+            if (xhr.responseType === 'text') {
+                result = xhr.responseText;
+            } else if (xhr.responseType === 'document') {
+                result = xhr.responseXML;
+            } else {
+                result = xhr.response;
+            }
+            _s.response(result, xhr.status);
+        });
+
+        // 请求出错
+        xhr.addEventListener('error', function (e) {
+            _s.error(xhr, xhr.status, e);
+        });
+
+        // 请求超时
+        xhr.addEventListener('timeout', function (e) {
+            _s.error(xhr, 408, e);
+        });
+
+        var useUrlParam = false;
+        var sType = _s.type.toUpperCase();
+        if (sType === 'GET' || sType === 'DELETE') {
+            useUrlParam = true;
+            _s.url += $Request.getUrlParam(_s.url, _s.data);
+        }
+        xhr.open(_s.type, _s.url, _s.async);
+        xhr.responseType = _s.dataType;
+        var headers_keys = Object.keys(_s.headers);
+        // 设置请求头
+        headers_keys.forEach(function (value, index, array) {
+            xhr.setRequestHeader(value, _s.headers[value]);
+        });
+        if (_s.async && _s.timeout) {
+            xhr.timeout = _s.timeout;
+        }
+        // xhr.send(useUrlParam ? null : $Request.getQueryData(_s.data));
+        xhr.send(useUrlParam ? null : JSON.stringify(_s.data));
+    },
+
+    getUrlParam: function (url, data) {
+        if (!data) {
+            return '';
+        }
+        var paramsStr = data instanceof Object ? $Request.getQueryString(data) : data;
+        return (url.indexOf('?') !== -1) ? paramsStr : '?' + paramsStr;
+    },
+
+    getQueryData: function (data) {
+        if (!data) {
+            return null;
+        }
+        if (typeof data === 'string') {
+            return data;
+        }
+        if (data instanceof FormData) {
+            return data;
+        }
+        return $Request.getQueryString(data);
+    },
+
+    getQueryString: function (data) {
+        var paramsArr = [];
+        if (data instanceof Object) {
+            Object.keys(data).forEach(function (key) {
+                var val = data[key];
+                paramsArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
+            });
+        }
+        return paramsArr.join('&');
+    }
+};
+var $Config = {
+    data: function () {
+        return {
+            isCollapse: false,
+        }
+    },
+    methods: {
+        /*主题色右侧菜单事件*/
+        themeCommandEvent: function (theme) {
+            let root = document.querySelector(":root");
+            Cookies.set('theme', theme);
+            root.style.setProperty("--themeColors", themeStyle[theme].themeColors);
+            root.style.setProperty("--themeTextColors", themeStyle[theme].themeTextColors);
+            root.style.setProperty("--themeSelectColors", themeStyle[theme].themeSelectColors);
+            root.style.setProperty("--headerBackground", themeStyle[theme].headerBackground);
+            root.style.setProperty("--headerTextColors", themeStyle[theme].headerTextColors);
+            root.style.setProperty("--leftBackground", themeStyle[theme].leftBackground);
+            root.style.setProperty("--leftTextColors", themeStyle[theme].leftTextColors);
+            root.style.setProperty("--buttonHoverColors", themeStyle[theme].buttonHoverColors);
+        },
+        /*左侧菜单展合*/
+        menuClose() {
+            var that = this;
+            if (that.isCollapse === true) {
+                that.isCollapse = false;
+                $('#app-main').css('--real-sidebar-width', '200px')
+                $('.left-title span').css('display', 'inline')
+            } else {
+                that.isCollapse = true;
+                $('#app-main').css('--real-sidebar-width', '64px')
+                $('.left-title span').css('display', 'none')
+            }
+            // 监听窗口大小变化
+            that.handleResize()
+        },
+        handleResize(){
+            // 监听窗口开合
+        }
+    },
+    beforeCreate: function () {
+    },
+
+    created: function () {
+    },
+
+    mounted: function () {
+        //设置主体
+        var $theme = Cookies.get('theme');
+        this.themeCommandEvent($theme ? $theme : 'index');
+    }
+};
+var $Layouts = {
+    data: function () {
+        return {
+            config: {
+                menuLayouts: 'left', permissions: true, breadcrumb: true,
+                header: {show: false, msg: '详细页面', back: '', callback: ''}, menu_id: 0,
+            },
+            menuRule:'index',
+            fastAdminPath:'/admin.php',
+            currentItemsKey:'currentItems',
+            layoutsLeftMenuEventKey:'layoutsLeftMenuEvent',
+            permissions: [],
+            layouts: {
+
+                tabs: {
+                    menuOpenIds: [],
+                    active: 0,
+                    menus: {},
+                    show: true,
+                    custom: false,
+                    openeds: [],
+                    headerParentId: 0
+                },
+
+                left: {
+                    menuOpenIds: [],
+                    active: '0',
+                    menus: {},
+                    show: true,
+                    custom: false,
+                    openeds: [],
+                    headerParentId: 0,
+                },
+
+                drawerFormsHeight: {'height': '600px'},
+                drawerFixedHeight: {'height': '480px'},
+                dialogFormsHeight: {'height': '480px'},
+                dialogFixedHeight: {'height': '480px'},
+            },
+            GalleryParams: {
+                models: '',
+                action: '/admin/framework/common/gallery/upload',
+                driver: 'local',
+                domain: '',
+                options: {
+                    max: 1,
+                    size: 20,
+                    suffix: 'bmp,gif,jpg,jpeg,png',
+                    type: 1,
+                    cat: false,
+                    tabs: false,
+                    upload: true,
+                    addPage: false,
+                    addIcon: false,
+                },
+                fileTypeMaps: {
+                    '1': 'image', '2': 'media', '3': 'file'
+                },
+                postHeaders: {
+                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+                },
+                postData: {},
+                operation: {
+                    groupManage: false,
+                    groupMax: 6,
+                    imageTotal: 0,
+                    dialog: false,
+                    loading: false,
+                    loadingMsg: '',
+                    error: false
+                },
+                search: {
+                    group_id: 0,
+                    page: 1,
+                    keyword: '',
+                    size: 12,
+                    type: 1
+                },
+                size:0,
+                groupItems: [],
+                imagesItems: [],
+                selected: [],
+            },
+            CenterParams:{
+                // 监测抽屉鼠标事件
+                mousedownClassBol: false,//抽屉遮盖层误触
+                dialogClassModel: '',//抽屉遮盖层误触
+                // 监测抽屉鼠标事件 End.
+                loadingMsg:'正在加载数据,请稍后...',
+                dialog: false, loading: false,updatePasswordStatus:false,
+                action: '',
+                model: {name:'',account:'',password:''},
+                rules: {
+                    name: [
+                        { required: true, message: '请填写用户名', trigger: 'blur'}
+                    ],
+                    account: [
+                        { required: true, message: '请填写登录账号', trigger: 'blur'}
+                    ]
+                }
+            },
+        }
+    },
+    methods: {
+        copy(context){
+            let that = this
+            navigator.clipboard.writeText(context)
+                .then(()=>{
+                    that.$Message('复制成功', 'success');
+                })
+                .catch(err => {
+                    that.$Message('复制失败', 'warning');
+                })
+        },
+        /*格式化时间戳*/
+        formatTableDate: function (row, column, value) {
+            if ((typeof (value) === 'undefined') || parseInt(value) === 0) {
+                return '---';
+            }
+            return $Utils.formatDate('yyyy-MM-dd hh:mm:ss', value);
+        },
+
+        formatTableDay: function (row, column, value) {
+            if ((typeof (value) === 'undefined') || parseInt(value) === 0) {
+                return '---';
+            }
+            return $Utils.formatDate('yyyy-MM-dd', value);
+        },
+        /*确认信息*/
+        $Alerts: function (msg, successCallback, errorCallback, options) {
+            options = options ? options : {
+                type: 'warning',
+                lockScroll: true,
+                center: true,
+                confirm: '确定',
+                cancel: '取消',
+                showClose: true,
+                showCancelButton: true,
+            };
+            var that = this;
+            that.$confirm(msg, '系统提示', {
+                dangerouslyUseHTMLString: true,
+                confirmButtonText: options.confirm ? options.confirm : '确定',
+                cancelButtonText: options.cancel ? options.cancel : '取消',
+                type: options.type ? options.type : 'warning',
+                lockScroll: options.lockScroll ? options.lockScroll : false,
+                showClose: options.showClose ? options.showClose : true,
+                center: options.center ? options.center : true,
+                showCancelButton: options.showCancelButton ? options.showCancelButton : true,
+            }).then(function () {
+                if (successCallback) {
+                    successCallback();
+                }
+            }).catch(function () {
+                if (errorCallback) {
+                    errorCallback();
+                }
+            });
+        },
+
+        /*确认信息*/
+        $Confirm: function (msg, successCallback, errorCallback, options) {
+            var that = this;
+            options = options ? options : {};
+            var _s = Object.assign({
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+                type: 'warning',
+                center: true,
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                closeOnClickModal: true,
+                showCancelButton: true
+            }, options);
+            that.$confirm(msg, '系统提示', _s).then(function () {
+                if (successCallback) {
+                    successCallback();
+                }
+            }).catch(function () {
+                if (errorCallback) {
+                    errorCallback();
+                }
+            });
+        },
+
+        /*提示信息*/
+        $Message: function (msg, callback, type, duration) {
+            var that = this;
+            if (typeof callback === 'string') {
+                type = callback;
+            } else {
+                if (!type) {
+                    type = 'success';  //warning  error
+                }
+            }
+            duration = duration ? duration : 1500;
+            that.$message({
+                type: type, duration: duration, message: msg, dangerouslyUseHTMLString: true, onClose: function (res) {
+                    if (callback && (typeof callback) === 'function') {
+                        callback(res);
+                    }
+                }
+            });
+        },
+
+        $Loading: function () {
+            var loading = this.$loading({
+                lock: true,
+                text: 'Loading',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0, 0, 0, 0.7)'
+            });
+            setTimeout(() => {
+                loading.close();
+            }, 2000);
+        },
+        emptyChange: function () {
+        },
+        PermissionsCallbackEvent: function (res) {
+            return true;
+        },
+        layoutsLeftMenuEvent: function (key, keyPath, e) {
+            var that = this;
+            var menuItems = e.$attrs.items;
+            var $loading = that.$loading({
+                lock: true,
+                background: 'rgba(255, 255, 255, 0.4)'
+            });
+            if ((typeof e.$attrs.items) != 'object') {
+                if (!$Validator.json(e.$attrs.items)) {
+                    return true;
+                }
+                menuItems = JSON.parse(e.$attrs.items);
+            }
+
+            var currentItems = Cookies.getJSON(that.currentItemsKey);
+            Cookies.set(that.layoutsLeftMenuEventKey, menuItems.id);
+            Cookies.set(that.currentItemsKey, menuItems);
+            that.layoutsTabsMenuEvent(menuItems);
+            $Request.get(menuItems.path, {}, function (status) {
+                $loading.close();
+                if (status !== 200) {
+                    Cookies.set(that.currentItemsKey, currentItems);
+                    Cookies.set(that.layoutsLeftMenuEventKey, currentItems.id);
+                    $Request.get(currentItems.path, {});
+                }
+            });
+        },
+        layoutsLeftMenuEventSet: function (menuItems) {
+            var that = this
+            var $loading = this.$loading({
+                lock: true,
+                background: 'rgba(255, 255, 255, 0.4)'
+            });
+            var currentItems = Cookies.getJSON(that.currentItemsKey);
+            Cookies.set(that.layoutsLeftMenuEventKey, menuItems.id);
+            Cookies.set(that.currentItemsKey, menuItems);
+            $Request.get(menuItems.path, {}, function (status) {
+                $loading.close();
+                if (status !== 200) {
+                    Cookies.set(that.currentItemsKey, currentItems);
+                    Cookies.set(that.layoutsLeftMenuEventKey, currentItems.id);
+                    $Request.get(currentItems.path, {});
+                }
+            });
+        },
+        layoutsTabsMenuClickEvent: function (e) {
+            var that = this;
+            if (!that.layouts.tabs.show) return false;
+            if (!that.layouts.tabs.active || parseInt(that.layouts.tabs.active) === 0) {
+                Cookies.remove(that.currentItemsKey);
+                Cookies.remove(that.layoutsLeftMenuEventKey);
+                $Request.get('/admin', {});
+                return true;
+            }
+            $.each(that.layouts.tabs.menus, function (key, val) {
+                if (parseInt(val.id) === parseInt(that.layouts.tabs.active)) {
+                    that.layoutsLeftMenuEventSet(val);
+                    return true;
+                }
+            });
+        },
+        layoutsTabsMenuRemoveEvent: function (e) {
+            var that = this;
+            var _Key = 0;
+            if (!that.layouts.tabs.show) return false;
+            $.each(that.layouts.tabs.menus, function (key, val) {
+                if (parseInt(val.id) === e) {
+                    _Key = (key + 1);
+                    that.layouts.tabs.menus.splice(key, 1);
+                    return false;
+                }
+            });
+            var _Length = that.layouts.tabs.menus.length;
+            if (_Length < 1) {
+                sessionStorage.removeItem('9ca5hgd13b48hfcddfdab76c63ddf8u2');
+                Cookies.remove(that.currentItemsKey);
+                Cookies.remove(that.layoutsLeftMenuEventKey);
+                $Request.get('/admin', {});
+                return true;
+            }
+            sessionStorage.setItem('9ca5hgd13b48hfcddfdab76c63ddf8u2', JSON.stringify(that.layouts.tabs.menus));
+            if (parseInt(that.layouts.tabs.active) === e) {
+                if (parseInt(_Key) === 1) {
+                    that.layoutsLeftMenuEventSet(that.layouts.tabs.menus[0]);
+                    return true;
+                }
+                that.layoutsLeftMenuEventSet(that.layouts.tabs.menus[_Key - 2]);
+            }
+            return true;
+        },
+        layoutsTabsMenuEvent: function (items) {
+            var that = this;
+            var _isS = true;
+            if (!that.layouts.tabs.show) return false;
+            $.each(that.layouts.tabs.menus, function (key, val) {
+                if (parseInt(val.id) === parseInt(items.id)) {
+                    that.layouts.tabs.active = val.id;
+                    _isS = false;
+                    return true;
+                }
+            });
+            if (_isS === true) {
+                var menus = sessionStorage.getItem('9ca5hgd13b48hfcddfdab76c63ddf8u2');
+                if (menus) {
+                    menus = JSON.parse(menus);
+                    menus.push(items);
+                } else {
+                    menus = [items];
+                }
+                sessionStorage.setItem('9ca5hgd13b48hfcddfdab76c63ddf8u2', JSON.stringify(menus));
+                return true;
+            }
+        },
+        layoutsTabsMenuCommandEvent: function (e) {
+            var that = this;
+            if (!that.layouts.tabs.show) return false;
+            if (that.layouts.tabs.menus.length < 1) {
+                return true;
+            }
+            if (e === 'all') {
+                sessionStorage.removeItem('9ca5hgd13b48hfcddfdab76c63ddf8u2');
+                Cookies.remove(that.currentItemsKey);
+                Cookies.remove(that.layoutsLeftMenuEventKey);
+                $Request.get('/admin', {});
+                return true;
+            } else if (e === 'other') {
+                var tabsMenus = [];
+                if (that.layouts.tabs.menus && that.layouts.tabs.menus.length > 0) {
+                    if (parseInt(this.layouts.tabs.active) > 0) {
+                        $.each(that.layouts.tabs.menus, function (key, val) {
+                            if (parseInt(val.id) === parseInt(that.layouts.tabs.active)) {
+                                tabsMenus[0] = val;
+                            }
+                        });
+                        that.layouts.tabs.menus = tabsMenus;
+                        sessionStorage.setItem('9ca5hgd13b48hfcddfdab76c63ddf8u2', JSON.stringify(tabsMenus));
+                    } else {
+                        sessionStorage.removeItem('9ca5hgd13b48hfcddfdab76c63ddf8u2');
+                        Cookies.remove(that.currentItemsKey);
+                        Cookies.remove(that.layoutsLeftMenuEventKey);
+                        $Request.get('/admin', {});
+                    }
+                }
+            } else {
+                if (parseInt(this.layouts.tabs.active) > 0) {
+                    that.layoutsTabsMenuRemoveEvent(that.layouts.tabs.active);
+                }
+            }
+        },
+        getLayoutsTabsMenus: function (items) {
+            var that = this;
+            if (!that.layouts.tabs.show) return false;
+            that.layouts.tabs.menus = [];
+            if (!that.layouts.tabs.show) return true;
+            var currentItems = sessionStorage.getItem('9ca5hgd13b48hfcddfdab76c63ddf8u2');
+            if (!currentItems) {
+                return true;
+            }
+            currentItems = JSON.parse(currentItems);
+            that.layouts.tabs.show = true;
+            that.layouts.tabs.menus = currentItems;
+
+        },
+        /*获取页面操作项*/
+        getUserOperationPermissions: function (menu_rule) {
+            var that = this;
+            $Request.postJson(that.fastAdminPath + '/vue/operationPermissions', {menu_rule: menu_rule}, function (res) {
+                if (res.code === 200) {
+                    that.permissions = res.result;
+                    // console.log(that.permissions);
+                    that.PermissionsCallbackEvent(res.result);
+                }
+            });
+        },
+        redirectPage: function (url, data, type) {
+            var that = this;
+            var backLoading = that.$loading({
+                lock: true,
+                background: 'rgba(255, 255, 255, 0.4)'
+            });
+            switch (type) {
+                case 'load':
+                    that.layouts.loading = true;
+                    $Request.load(url, data);
+                    break;
+                case 'open':
+                    backLoading.close();
+                    $Request.open(url, data);
+                    break;
+                case 'reload':
+                    window.location.reload();
+                    break;
+                case 'post':
+                    $Request.postJson(url, data, function (res) {
+                        backLoading.close();
+                        that.$Message('成功!');
+                    });
+                    break;
+                default:
+                    that.layouts.loading = true;
+                    $Request.get(url, data);
+                    break;
+            }
+
+            return true;
+        },
+        /*计算页面高度*/
+        computingWindowHeight: function (reload) {
+            var that = this;
+            if (reload === true) {
+                if (that.layouts.isCollapse) {
+                    that.layouts.isCollapse = false;
+                    that.layouts.menuWidth = {'width': '220px !important'}
+                } else {
+                    that.layouts.isCollapse = true;
+                    that.layouts.menuWidth = {'width': '64px !important'}
+                }
+                if (!that.layouts.left.show) {
+                    that.layouts.isCollapse = false;
+                    that.layouts.menuWidth = {'width': '0 !important'};
+                }
+            }
+
+
+            var documentClientHeight = document.documentElement.clientHeight;
+            that.layouts.containerHeight = {
+                'height': (documentClientHeight - 20) + 'px',
+            };
+
+            that.layouts.mainHeight = {
+                'min-height': (documentClientHeight - 120) + 'px',
+            };
+
+            that.layouts.drawerFormsHeight = {
+                'max-height': parseInt((documentClientHeight * 0.71) - 120) + 'px'
+            };
+
+            that.layouts.dialogFormsHeight = {
+                'max-height': parseInt((documentClientHeight * 0.81) - 120) + 'px'
+            };
+
+            that.layouts.drawerFixedHeight = {
+                'height': (documentClientHeight - 131) + 'px',
+            };
+
+            that.layouts.dialogFixedHeight = {
+                'height': (documentClientHeight - 380) + 'px',
+            };
+
+            that.layouts.windowHeight = documentClientHeight - 120;
+        },
+        handleCommand: function (command) {
+            var that = this;
+            switch (command) {
+                case 'logout': //退出
+                    that.logout();
+                    break;
+                case 'clear_cache':
+                    that.clearCache();
+                    break;
+                case 'center':
+                    that.centerDialogOpen();
+                    break;
+                default:
+                    break;
+            }
+        },
+        logout: function () {
+            $Request.get('/admin/passport/logout', {});
+        },
+        clearCache: function () {
+            this.redirectPage('/admin/framework/common/cacheClear', {}, 'post')
+        },
+        centerDialogOpen: function () {
+            $Center.CenterDialogOpen();
+        },
+    },
+    beforeCreate: function () {
+    },
+
+    created: function () {
+        var that = this;
+        var path = window.location.pathname.split('/')[1];
+        path = path === undefined ? '' : '/' + path;
+        that.layoutsLeftMenuEventKey = $('meta[name="layouts-left"]').attr('content');
+        that.currentItemsKey = $('meta[name="current-items"]').attr('content');
+        that.fastAdminPath = path;
+        that.getUserOperationPermissions(that.menuRule);
+    },
+
+    mounted: function () {
+        var that = this;
+        that.computingWindowHeight(true);
+        $(window).resize(function () {
+            that.computingWindowHeight(false);
+        });
+    }
+};
+var $Tables = {
+    data: function () {
+        return {
+            tables: {
+                remove: {url: '', msg: '', field: ''},
+                status: {url: '', msg: '', field: '', maps: {1: '禁用', 2: '启用'}},
+                sort: {url: '', item: '', field: ''},
+                selects: [],
+                options: {
+                    cell: true,
+                    loading: true,
+                    loadingMsg: '正在加载数据,请稍后...'
+                },
+                url: '', search: {},
+                prop: 'id',
+                orderBy: 'desc',
+                pagination: {
+                    layouts: 'total, sizes, prev, pager, next, jumper',
+                    sizes: [15, 30, 50, 100, 300, 500],
+                    page: 1,
+                    size: 15,
+                    total: 20,
+                },
+                data: []
+            },
+        }
+    },
+
+    methods: {
+        formatTableColumn: function (row, column, value) {
+
+        },
+        tablesCellMoveEvent: function (row, column, cell, event) {
+            var that = this;
+            if (column.filterPlacement === 'false' || !that.tables.options.cell) {
+                return false;
+            }
+            event.stopPropagation();
+            if ($(cell).find('.cell').hasClass('Va-table-move')) {
+                return false;
+            } else {
+                $('.cell').removeClass('Va-table-move');
+                $('.Va-table-move-close').remove();
+                if (!row[column.property]) {
+                    return false;
+                }
+                $(cell).find('.cell').append('<i class="el-icon-close Va-table-move-close" onclick="removeTableMoveEvent(this)"></i>');
+                $(cell).find('.cell').addClass('Va-table-move');
+                if (($(cell).width() - 20) > $(cell).parent().find('.Va-table-move').width()) {
+                    $('.cell').removeClass('Va-table-move');
+                    $('.Va-table-move-close').remove();
+                }
+            }
+        },
+
+        tablesPaginationSizeChange: function (size) {
+            var that = this;
+            that.tables.pagination.size = size;
+            that.tablesGetTableList();
+        },
+
+        tablesPaginationCurrentChange: function (page) {
+            var that = this;
+            that.tables.pagination.page = page;
+            that.$refs.formContainerTables.clearSelection();
+            that.tablesGetTableList();
+        },
+
+        /*排序发生改变时触发*/
+        tablesPaginationSortChange: function (rows) {
+            var that = this;
+            that.$set(that.tables, 'orderBy', rows.orderBy);
+            if (typeof rows.column.sortBy === 'undefined') {
+                that.$set(that.tables, 'prop', rows.prop);
+            } else {
+                that.$set(that.tables, 'prop', rows.column.sortBy);
+            }
+            that.tablesGetTableList();
+        },
+
+        /*多选发生改变时触发*/
+        tablesSelectChange: function (rows) {
+            var that = this;
+            that.selects = rows;
+            that.$set(that.tables, 'selects', rows);
+        },
+
+        tablesClearSelect: function () {
+            var that = this;
+            that.$nextTick(function () {
+                that.$refs.formContainerTables.clearSelection();
+            })
+        },
+
+        getTablesSelected: function () {
+            var that = this;
+            if (!that.tables.selects.length || that.tables.selects.length <= 0) {
+                return [];
+            }
+            var selects_ids = [];
+            that.tables.selects.forEach(function (item, index) {
+                selects_ids.push(item.id);
+            });
+            if (!selects_ids || selects_ids.length <= 0) {
+                return [];
+            }
+            return selects_ids;
+        },
+
+        tablesGetTableList: function () {
+            var that = this;
+            if (!that.tablesGetTableListFront()) {
+                return false;
+            }
+            if (!that.tables.url) {
+                that.tables.url = window.location.href;
+            }
+            that.tables.options.loading = true;
+            that.tables.search.page = that.tables.pagination.page;
+            that.tables.search.size = that.tables.pagination.size;
+            that.tables.search.orderBy = that.tables.orderBy;
+            that.tables.search.prop = that.tables.prop;
+            $Request.postJson(that.tables.url, that.tables.search, function (res) {
+                if (that.tablesGetTablesListsAfter(res)) {
+                    if ((typeof (res) === 'undefined')) {
+                        return false;
+                    }
+                    if ((typeof (res.result) === 'undefined')) {
+                        return false;
+                    }
+                    // console.log(that.tables.data);
+                    that.tables.options.loading = false;
+                    that.tables.data = res.result.rows ? res.result.rows : res.result.data;
+                    that.tables.pagination.total = res.result.total;
+                }
+                that.tablesGetTablesListsFinish(res);
+            })
+            if (that.parking && that.parking.search.store_id){
+                that.getParkingList()
+            }
+        },
+
+        tablesGetTableListFront: function () {
+            return true;
+        },
+        tablesGetTablesListsAfter: function () {
+            return true;
+        },
+        tablesGetTablesListsFinish: function () {
+            return true;
+        },
+
+        tablesRowsRemove: function (rows, params) {
+            var that = this;
+            if (!that.tables.remove.url) {
+                return false;
+            }
+            var requestData = {};
+
+            if (params) {
+                requestData = params;
+            }
+
+            that.tables.remove.msg = that.tables.remove.msg ? that.tables.remove.msg : '确认删除当前数据吗?';
+            that.tables.remove.field = that.tables.remove.field ? that.tables.remove.field : 'id';
+            if (!rows[that.tables.remove.field]) {
+                return false;
+            }
+            requestData[that.tables.remove.field] = rows[that.tables.remove.field];
+
+            that.$confirm(that.tables.remove.msg, '操作提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning',
+                center: true,
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+            }).then(function () {
+                $Request.postJson(that.tables.remove.url, requestData, function (res) {
+                    if (res.code === 200) {
+                        that.$message({
+                            message: res.message, type: 'success', duration: 2400, onClose: function () {
+                            }
+                        });
+                        that.tablesGetTableList();
+                    } else {
+                        that.$message({
+                            message: res.message, type: 'error', duration: 2400, onClose: function () {
+                            }
+                        });
+                    }
+                })
+            }).catch(function () {
+
+            });
+        },
+
+        tablesRowsStatus: function (rows, params) {
+            var that = this;
+
+
+            if (!that.tables.status.url || !that.tables.status.field) {
+                return false;
+            }
+
+            if (!rows[that.tables.status.field] && rows[that.tables.status.field] !== 0) {
+                return false;
+            }
+
+            if (!that.tables.status.maps[rows[that.tables.status.field]]) {
+                return false;
+            }
+
+            that.tables.status.msg = '确认' + that.tables.status.maps[rows[that.tables.status.field]] + '当前数据吗?';
+
+
+            var requestData = {};
+
+            if (params) {
+                requestData = params;
+            }
+
+            requestData[that.tables.status.field] = rows[that.tables.status.field];
+
+            that.$confirm(that.tables.status.msg, '操作提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning',
+                center: false,
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+            }).then(function () {
+                $Request.postJson(that.tables.status.url, requestData, function (res) {
+                    if (res.code === 200) {
+                        that.$message({
+                            message: res.message, type: 'success', duration: 2400, onClose: function () {
+                            }
+                        });
+                        that.tablesGetTableList();
+                    } else {
+                        that.$message({
+                            message: res.message, type: 'error', duration: 2400, onClose: function () {
+                            }
+                        });
+                    }
+                })
+            }).catch(function () {
+
+            });
+        },
+
+        tablesRowsSort: function (rows) {
+            var that = this;
+            if (!that.tables.sort.url) {
+                return false;
+            }
+            var requestData = {};
+            that.tables.sort.field = that.tables.sort.field ? that.tables.sort.field : 'id';
+            that.tables.sort.item = that.tables.sort.item ? that.tables.sort.item : 'sort';
+            if (!rows[that.tables.sort.field]) {
+                return false;
+            }
+            if (!rows[that.tables.sort.item]) {
+                return false;
+            }
+            requestData[that.tables.sort.field] = rows[that.tables.sort.field];
+            requestData[that.tables.sort.item] = rows[that.tables.sort.item];
+            $Request.postJson(that.tables.sort.url, requestData, function (res) {
+                if (res.code === 200) {
+                    that.$message({message: res.message, type: 'success', duration: 2100});
+                    that.tablesGetTableList();
+                } else {
+                    that.$message({message: res.message, type: 'error', duration: 2100});
+                }
+            })
+        },
+
+        tablesRowsType: function (rows) {
+            var that = this;
+            if (!that.tables.type.url) {
+                return false;
+            }
+            var requestData = {};
+            that.tables.type.field = that.tables.type.field ? that.tables.type.field : 'id';
+            that.tables.type.item = that.tables.type.item ? that.tables.type.item : 'type';
+            if (!rows[that.tables.type.field]) {
+                return false;
+            }
+            if (!rows[that.tables.type.item]) {
+                return false;
+            }
+            requestData[that.tables.type.field] = rows[that.tables.type.field];
+            requestData[that.tables.type.item] = rows[that.tables.type.item];
+            $Request.postJson(that.tables.type.url, requestData, function (res) {
+                if (res.code === 200) {
+                    that.$message({message: res.message, type: 'success', duration: 2100});
+                    that.tablesGetTableList();
+                } else {
+                    that.$message({message: res.message, type: 'error', duration: 2100});
+                }
+            })
+        },
+
+        // 公共执行操作
+        tablesRowsOperate: function (url, params, msg = '确定要执行当前操作吗?') {
+            var that = this;
+
+            var requestData = {};
+
+            if (params) {
+                requestData = params;
+            }
+
+            that.$confirm(msg, '操作提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning',
+                center: false,
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+            }).then(function () {
+                $Request.postJson(url, requestData, function (res) {
+                    if (res.code === 200) {
+                        that.$message({
+                            message: res.message, type: 'success', duration: 2400, onClose: function () {
+                            }
+                        });
+                        that.tablesGetTableList();
+                    } else {
+                        that.$message({
+                            message: res.message, type: 'error', duration: 2400, onClose: function () {
+                            }
+                        });
+                    }
+                })
+            }).catch(function () {
+
+            });
+        },
+
+        tablesSearchEvent: function () {
+            this.tables.pagination.page = 1;
+            this.tablesGetTableList();
+        },
+
+        tablesResetsEvent: function () {
+
+        },
+    },
+
+    mounted: function () {
+        var that = this;
+        that.tablesGetTableList();
+    },
+
+    beforeCreate: function () {
+        var that = this;
+    },
+
+    created: function () {
+
+
+    }
+};
+var $DrawerForms = {
+    data: function () {
+        return {
+            drawerFormsOptions: {
+                models: 'drawerForms',
+                refs: 'create.model',
+                status: false,
+            },
+            drawerOpens: [],
+            __key: '',
+            drawerForms: {},
+
+            // 监测抽屉鼠标事件
+            mousedownClassBol: false,//抽屉遮盖层误触
+            drawerClassModel: '',//抽屉遮盖层误触
+            // 监测抽屉鼠标事件 End.
+        }
+    },
+    methods: {
+        // 监测抽屉鼠标事件
+        handleWrapperMousedown(e) {
+            var that = this;
+            // 如果为true,则表示点击发生在遮罩层
+            that.drawerClassModel = !!e.target.classList.contains('el-drawer__container')
+        },
+        handleWrapperMouseup(e) {
+            var that = this;
+            if ((!!e.target.classList.contains('el-drawer__container')) && that.drawerClassModel) {
+                that.drawerFormsCloses(that.drawerFormsOptions.models);
+            }
+        },
+        // 监测抽屉鼠标事件 End.
+
+        drawerFormsCloses: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.drawerFormsOptions.models = model;
+
+            that[that.drawerFormsOptions.models].drawer = false;
+            that[that.drawerFormsOptions.models].loading = false;
+            if (that.drawerOpens.length > 0) {
+                that.drawerOpens.splice(that.drawerOpens.length - 1)
+                that.drawerFormsOptions.models = that.drawerOpens[that.drawerOpens.length - 1] ? that.drawerOpens[that.drawerOpens.length - 1] : 'drawerForms'
+            }
+            if (that.$refs[that.drawerFormsOptions.refs]) {
+                setTimeout(function () {
+                    that.$refs[that.drawerFormsOptions.refs].resetFields();
+                }, 500);
+            }
+        },
+
+        drawerFormsBeforeCloses: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.drawerFormsOptions.models = model;
+            // console.log(that.drawerFormsOptions.models);
+            that[that.drawerFormsOptions.models].drawer = false;
+            that[that.drawerFormsOptions.models].loading = false;
+        },
+
+        drawerFormsSubmits: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.drawerFormsOptions.models = model;
+            /*防止重复提交*/
+            if (that[that.drawerFormsOptions.models].loading) {
+                return false;
+            }
+            if ((typeof (that.$refs[that.drawerFormsOptions.refs]) === 'undefined')) {
+                that[that.drawerFormsOptions.models].loading = true;
+                var formsdrawerFunction = that.drawerFormsOptions.models + 'FormsSubmits';
+                if (that.hasOwnProperty(formsdrawerFunction)) {
+                    that[formsdrawerFunction](that[that.drawerFormsOptions.models].model);
+                } else {
+                    that.drawerFormsRequests(that[that.drawerFormsOptions.models].model);
+                }
+                that[that.drawerFormsOptions.models].loading = false;
+                return true;
+            } else {
+                that.$refs[that.drawerFormsOptions.refs].validate(function (valid) {
+                    if (valid) {
+                        that[that.drawerFormsOptions.models].loading = true;
+                        var formsdrawerFunction = that.drawerFormsOptions.models + 'FormsSubmits';
+                        if (that.hasOwnProperty(formsdrawerFunction)) {
+                            that[formsdrawerFunction](that[that.drawerFormsOptions.models].model);
+                        } else {
+                            that.drawerFormsRequests(that[that.drawerFormsOptions.models].model);
+                        }
+                    } else {
+                        that[that.drawerFormsOptions.models].loading = false;
+                    }
+                });
+            }
+        },
+
+        drawerFormsOpens: function (model) {
+            var that = this;
+            that.config.__key = $Request.random(12);
+            that.drawerFormsOptions.models = model;
+            if ((typeof (model) === 'undefined') || (typeof (model) === 'object')) {
+                that.drawerFormsOptions.models = 'drawerForms';
+            }
+            if ((typeof (that[that.drawerFormsOptions.models])) === 'undefined') {
+                that[that.drawerFormsOptions.models] = {
+                    drawer: false,
+                    loading: false,
+                    action: '',
+                    model: {},
+                    rules: {}
+                };
+            }
+            if ((typeof (that[that.drawerFormsOptions.models].drawer)) === 'undefined') {
+                that[that.drawerFormsOptions.models].drawer = false;
+            }
+
+            if ((typeof (that[that.drawerFormsOptions.models].loading)) === 'undefined') {
+                that[that.drawerFormsOptions.models].loading = false;
+            }
+            if ((typeof (that[that.drawerFormsOptions.models].loadingTables)) === 'undefined') {
+                that[that.drawerFormsOptions.models].loadingTables = true;
+            }
+            if ((typeof (that[that.drawerFormsOptions.models].model)) === 'undefined') {
+                that[that.drawerFormsOptions.models].model = {};
+            }
+
+            if ((typeof (that[that.drawerFormsOptions.models].rules)) === 'undefined') {
+                that[that.drawerFormsOptions.models].rules = {};
+            }
+
+            that.drawerFormsOptions.refs = that.drawerFormsOptions.models + '.model';
+            that.drawerFormsOptions.status = true;
+            that.drawerOpens.push(that.drawerFormsOptions.models);
+            that[that.drawerFormsOptions.models].drawer = true;
+            that[that.drawerFormsOptions.models].loading = false;
+            if (!(typeof (that.$refs[that.drawerFormsOptions.refs]) === 'undefined')) {
+                that.$refs[that.drawerFormsOptions.refs].resetFields();
+            }
+            return true;
+        },
+
+        drawerFormsRequests: function (model) {
+            var that = this;
+            if (!that[that.drawerFormsOptions.models].action) {
+                console.error('$drawerForms:Forms component does not configure submit parameters!');
+                that[that.drawerFormsOptions.models].loading = false;
+                return false;
+            }
+            $Request.postJson(that[that.drawerFormsOptions.models].action, model, function (res) {
+                if (res.code === 200) {
+                    that.$message({
+                        message: res.message, type: 'success', duration: 1500, onClose: function () {
+                            if (that.hasOwnProperty('tablesGetTableList')) {
+                                that[that.drawerFormsOptions.models].loading = false;
+                                that[that.drawerFormsOptions.models].drawer = false;
+                                if (that[that.drawerFormsOptions.models].loadingTables) {
+                                    that.tablesGetTableList();
+                                }
+
+                                that.drawerFormsRequestsAfter(res);
+                            }
+                            if (that[that.drawerFormsOptions.models].success) {
+                                var success = that[that.drawerFormsOptions.models].success;
+                                if (that.hasOwnProperty(success)) {
+                                    that[success](res)
+                                }
+                            }
+                        }
+                    });
+
+                } else {
+                    that[that.drawerFormsOptions.models].loading = false;
+                    that.$message({message: res.message, type: 'error', duration: 1500});
+                }
+            });
+        },
+
+        drawerFormsRequestsAfter: function () {
+            return true;
+        },
+
+        drawerFormsRequestsErrors: function () {
+            var that = this;
+        },
+
+        drawerFormsValidateErrors: function (forms) {
+            var that = this;
+        },
+
+        drawerListPageFormsOpens:function (model) {
+            var that = this;
+            var __table = that[model].model.__table;
+            $Request.postJson('/admin/arts/setup/pageGetSetup', {__table: __table}, function (res) {
+                if(res.code === 200){
+                    if(res.result && !Array.isArray(res.result)) {
+                        that[model].model = res.result;
+                    }
+                    that[model].model.__table = __table;
+                }
+                that.drawerFormsOpens(model);
+            })
+        }
+    },
+
+    mounted: function () {
+
+    },
+    beforeCreate: function () {
+        var that = this;
+    },
+
+    created: function () {
+        var that = this;
+    }
+};
+var $DialogForms = {
+    data: function () {
+        return {
+            dialogFormsOptions: {
+                models: 'dialogForms',
+                refs: 'create.model',
+                status: false,
+            },
+            dialogOpens: [],
+            __key: '',
+            dialogForms: {},
+            // 监测抽屉鼠标事件
+            mousedownClassBol: false,//抽屉遮盖层误触
+            dialogClassModel: '',//抽屉遮盖层误触
+            // 监测抽屉鼠标事件 End.
+        }
+    },
+    methods: {
+        // 监测抽屉鼠标事件
+        handleWrapperMousedown(e) {
+            var that = this;
+            // 如果为true,则表示点击发生在遮罩层
+            that.dialogClassModel = !!e.target.classList.contains('el-dialog__wrapper')
+        },
+        handleWrapperMouseup(e) {
+            var that = this;
+            if ((!!e.target.classList.contains('el-dialog__wrapper')) && that.dialogClassModel) {
+                that.dialogFormsCloses(that.dialogFormsOptions.models);
+            }
+        },
+        // 监测抽屉鼠标事件 End.
+
+        dialogFormsCloses: function (model) {
+            var that = this;
+
+            if (model && typeof model == 'string') that.dialogFormsOptions.models = model;
+
+            that[that.dialogFormsOptions.models].dialog = false;
+            that[that.dialogFormsOptions.models].loading = false;
+            if (that.dialogOpens.length > 0) {
+                that.dialogOpens.splice(that.dialogOpens.length - 1)
+                that.dialogFormsOptions.models = that.dialogOpens[that.dialogOpens.length - 1] ? that.dialogOpens[that.dialogOpens.length - 1] : 'drawerForms'
+            }
+            if (that.$refs[that.dialogFormsOptions.refs]) {
+                setTimeout(function () {
+                    that.$refs[that.dialogFormsOptions.refs].resetFields();
+                }, 500);
+            }
+        },
+
+        dialogFormsBeforeCloses: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.dialogFormsOptions.models = model;
+            // console.log(that.dialogFormsOptions.models);
+            that[that.dialogFormsOptions.models].dialog = false;
+            that[that.dialogFormsOptions.models].loading = false;
+        },
+
+        dialogFormsSubmits: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.dialogFormsOptions.models = model;
+            /*防止重复提交*/
+            if (that[that.dialogFormsOptions.models].loading) {
+                return false;
+            }
+            if ((typeof (that.$refs[that.dialogFormsOptions.refs]) === 'undefined')) {
+                that[that.dialogFormsOptions.models].loading = true;
+                var formsdialogFunction = that.dialogFormsOptions.models + 'FormsSubmits';
+                if (that.hasOwnProperty(formsdialogFunction)) {
+                    that[formsdialogFunction](that[that.dialogFormsOptions.models].model);
+                } else {
+                    that.dialogFormsRequests(that[that.dialogFormsOptions.models].model);
+                }
+                that[that.dialogFormsOptions.models].loading = false;
+                return true;
+            } else {
+                that.$refs[that.dialogFormsOptions.refs].validate(function (valid) {
+                    if (valid) {
+                        that[that.dialogFormsOptions.models].loading = true;
+                        var formsdialogFunction = that.dialogFormsOptions.models + 'FormsSubmits';
+                        if (that.hasOwnProperty(formsdialogFunction)) {
+                            that[formsdialogFunction](that[that.dialogFormsOptions.models].model);
+                        } else {
+                            that.dialogFormsRequests(that[that.dialogFormsOptions.models].model);
+                        }
+                    } else {
+                        that[that.dialogFormsOptions.models].loading = false;
+                    }
+                });
+            }
+        },
+
+        dialogFormsOpens: function (model) {
+            var that = this;
+            that.config.__key = $Request.random(12);
+            that.dialogFormsOptions.models = model;
+            if ((typeof (model) === 'undefined') || (typeof (model) === 'object')) {
+                that.dialogFormsOptions.models = 'dialogForms';
+            }
+            if ((typeof (that[that.dialogFormsOptions.models])) === 'undefined') {
+                that[that.dialogFormsOptions.models] = {
+                    dialog: false,
+                    loading: false,
+                    action: '',
+                    model: {},
+                    rules: {}
+                };
+            }
+            if ((typeof (that[that.dialogFormsOptions.models].dialog)) === 'undefined') {
+                that[that.dialogFormsOptions.models].dialog = false;
+            }
+
+            if ((typeof (that[that.dialogFormsOptions.models].loading)) === 'undefined') {
+                that[that.dialogFormsOptions.models].loading = false;
+            }
+            if ((typeof (that[that.dialogFormsOptions.models].loadingTables)) === 'undefined') {
+                that[that.dialogFormsOptions.models].loadingTables = true;
+            }
+            if ((typeof (that[that.dialogFormsOptions.models].model)) === 'undefined') {
+                that[that.dialogFormsOptions.models].model = {};
+            }
+
+            if ((typeof (that[that.dialogFormsOptions.models].rules)) === 'undefined') {
+                that[that.dialogFormsOptions.models].rules = {};
+            }
+
+            that.dialogFormsOptions.refs = that.dialogFormsOptions.models + '.model';
+            that.dialogFormsOptions.status = true;
+            that[that.dialogFormsOptions.models].dialog = true;
+            that[that.dialogFormsOptions.models].loading = false;
+            if (!(typeof (that.$refs[that.dialogFormsOptions.refs]) === 'undefined')) {
+                that.$refs[that.dialogFormsOptions.refs].resetFields();
+            }
+            return true;
+        },
+
+        dialogFormsRequests: function (model) {
+            var that = this;
+            if (!that[that.dialogFormsOptions.models].action) {
+                console.error('$dialogForms:Forms component does not configure submit parameters!');
+                that[that.dialogFormsOptions.models].loading = false;
+                return false;
+            }
+            $Request.postJson(that[that.dialogFormsOptions.models].action, model, function (res) {
+                if (res.code === 200) {
+                    that.$message({
+                        message: res.message, type: 'success', duration: 1500, onClose: function () {
+                            if (that.hasOwnProperty('tablesGetTableList')) {
+                                that[that.dialogFormsOptions.models].loading = false;
+                                that[that.dialogFormsOptions.models].dialog = false;
+                                if (that[that.dialogFormsOptions.models].loadingTables) {
+                                    that.tablesGetTableList();
+                                    that.tablesDialogGetTableList();
+                                }
+
+                                that.dialogFormsRequestsAfter(res);
+                            }
+                            if (that[that.dialogFormsOptions.models].success) {
+                                that[that.dialogFormsOptions.models].loading = false;
+                                var success = that[that.dialogFormsOptions.models].success;
+                                if (that.hasOwnProperty(success)) {
+                                    that[success](res)
+                                }
+                            }
+                        }
+                    });
+
+                } else {
+                    that[that.dialogFormsOptions.models].loading = false;
+                    that.$message({message: res.message, type: 'error', duration: 1500});
+                }
+            });
+        },
+
+        dialogFormsRequestsAfter: function () {
+            return true;
+        },
+
+        dialogFormsRequestsErrors: function () {
+            var that = this;
+        },
+
+        dialogFormsValidateErrors: function (forms) {
+            var that = this;
+        },
+
+        dialogListPageFormsOpens:function (model) {
+            var that = this;
+            var __table = that[model].model.__table;
+            $Request.postJson('/admin/arts/setup/pageGetSetup', {__table: __table}, function (res) {
+                if(res.code === 200){
+                    if(res.result && !Array.isArray(res.result)) {
+                        that[model].model = res.result;
+                    }
+                    that[model].model.__table = __table;
+                }
+                that.dialogFormsOpens(model);
+            })
+        }
+    },
+
+    mounted: function () {
+
+    },
+    beforeCreate: function () {
+        var that = this;
+    },
+
+    created: function () {
+        var that = this;
+    }
+};
+var $Login = {
+    data: function () {
+        return {}
+    },
+    methods: {
+        hasClass: function (elem, cls) {
+            cls = cls || '';
+            if (cls.replace(/\s/g, '').length == 0) return false; //当cls没有参数时,返回false
+            return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ');
+        },
+        addClass(ele, cls) {
+            if (!this.hasClass(ele, cls)) {
+                ele.className = ele.className == '' ? cls : ele.className + ' ' + cls;
+            }
+        },
+        removeClass(ele, cls) {
+            if (this.hasClass(ele, cls)) {
+                var newClass = ' ' + ele.className.replace(/[\t\r\n]/g, '') + ' ';
+                while (newClass.indexOf(' ' + cls + ' ') >= 0) {
+                    newClass = newClass.replace(' ' + cls + ' ', ' ');
+                }
+                ele.className = newClass.replace(/^\s+|\s+$/g, '');
+            }
+        },
+        removeLocal(){
+            Cookies.remove('9ca8e8d13b4369cddfdab26c63d69ce2');
+            Cookies.remove('f63dcfe3c89a14e80c9cdf60b4b94f4b');
+            localStorage.clear();
+            sessionStorage.clear();
+        }
+    },
+    beforeCreate: function () {
+    },
+
+    created: function () {
+    },
+
+    mounted: function () {
+        //设置主体
+        var $theme = Cookies.get('theme');
+        this.themeCommandEvent($theme ? $theme : 'index');
+    }
+};
+var $TableDialog = {
+    data: function () {
+        return {
+            tableDialog:{
+                model: 'dialog'
+            }
+        }
+    },
+
+    methods: {
+        formatTableDialogColumn: function (row, column, value) {},
+        tablesDialogCellMoveEvent: function (row, column, cell, event) {
+            var that = this;
+            if (column.filterPlacement === 'false' || !that[that.tableDialog.models].options.cell) {
+                return false;
+            }
+            event.stopPropagation();
+            if ($(cell).find('.cell').hasClass('Va-table-move')) {
+                return false;
+            } else {
+                $('.cell').removeClass('Va-table-move');
+                $('.Va-table-move-close').remove();
+                if (!row[column.property]) {
+                    return false;
+                }
+                $(cell).find('.cell').append('<i class="el-icon-close Va-table-move-close" onclick="removeTableMoveEvent(this)"></i>');
+                $(cell).find('.cell').addClass('Va-table-move');
+                if (($(cell).width() - 20) > $(cell).parent().find('.Va-table-move').width()) {
+                    $('.cell').removeClass('Va-table-move');
+                    $('.Va-table-move-close').remove();
+                }
+            }
+        },
+
+        tablesDialogPaginationSizeChange: function (size) {
+            var that = this;
+            that[that.tableDialog.models].pagination.size = size;
+            that.tablesDialogGetTableList();
+        },
+
+        tablesDialogPaginationCurrentChange: function (page) {
+            var that = this;
+            that[that.tableDialog.models].pagination.page = page;
+            that.$refs.formContainerTables.clearSelection();
+            that.tablesDialogGetTableList();
+        },
+
+        /*排序发生改变时触发*/
+        tablesDialogPaginationSortChange: function (rows) {
+            var that = this;
+            that.$set(that[that.tableDialog.models], 'orderBy', rows.orderBy);
+            if (typeof rows.column.sortBy === 'undefined') {
+                that.$set(that[that.tableDialog.models], 'prop', rows.prop);
+            } else {
+                that.$set(that[that.tableDialog.models], 'prop', rows.column.sortBy);
+            }
+            that.tablesDialogGetTableList();
+        },
+
+        /*多选发生改变时触发*/
+        tablesDialogSelectChange: function (rows) {
+            var that = this;
+            that.selects = rows;
+            that.$set(that[that.tableDialog.models], 'selects', rows);
+        },
+
+        tablesDialogClearSelect: function () {
+            var that = this;
+            that.$nextTick(function () {
+                that.$refs.formContainerTables.clearSelection();
+            })
+        },
+
+        getTablesDialogSelected: function () {
+            var that = this;
+            if (!that[that.tableDialog.models].selects.length || that[that.tableDialog.models].selects.length <= 0) {
+                return [];
+            }
+            var selects_ids = [];
+            that[that.tableDialog.models].selects.forEach(function (item, index) {
+                selects_ids.push(item.id);
+            });
+            if (!selects_ids || selects_ids.length <= 0) {
+                return [];
+            }
+            return selects_ids;
+        },
+
+        tablesDialogGetTableList: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+            if (!that.tablesDialogGetTableListFront()) {
+                return false;
+            }
+            if (!that[that.tableDialog.models].url) {
+                that[that.tableDialog.models].url = window.location.href;
+            }
+            that[that.tableDialog.models].options.loading = true;
+            that[that.tableDialog.models].search.page = that[that.tableDialog.models].pagination.page;
+            that[that.tableDialog.models].search.size = that[that.tableDialog.models].pagination.size;
+            that[that.tableDialog.models].search.orderBy = that[that.tableDialog.models].orderBy;
+            that[that.tableDialog.models].search.prop = that[that.tableDialog.models].prop;
+            $Request.postJson(that[that.tableDialog.models].url, that[that.tableDialog.models].search, function (res) {
+                if (that.tablesDialogGetTablesListsAfter(res)) {
+                    if ((typeof (res) === 'undefined')) {
+                        return false;
+                    }
+                    if ((typeof (res.result) === 'undefined')) {
+                        return false;
+                    }
+                    that[that.tableDialog.models].options.loading = false;
+                    that[that.tableDialog.models].data = res.result.rows ? res.result.rows : res.result.data;
+                    that[that.tableDialog.models].pagination.total = res.result.total;
+                }
+                that.tablesDialogGetTablesListsFinish(res);
+            })
+        },
+
+        tablesDialogGetTableListFront: function () {
+            return true;
+        },
+        tablesDialogGetTablesListsAfter: function () {
+            return true;
+        },
+        tablesDialogGetTablesListsFinish: function () {
+            return true;
+        },
+
+        tablesDialogRowsRemove: function (model, rows, params) {
+            var that = this;
+
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+
+            if (!that[that.tableDialog.models].remove.url) {
+                return false;
+            }
+            var requestData = {};
+
+            if (params) {
+                requestData = params;
+            }
+
+            that[that.tableDialog.models].remove.msg = that[that.tableDialog.models].remove.msg ? that[that.tableDialog.models].remove.msg : '确认删除当前数据吗?';
+            that[that.tableDialog.models].remove.field = that[that.tableDialog.models].remove.field ? that[that.tableDialog.models].remove.field : 'id';
+            if (!rows[that.tables.remove.field]) {
+                return false;
+            }
+            requestData[that[that.tableDialog.models].remove.field] = rows[that[that.tableDialog.models].remove.field];
+
+            that.$confirm(that[that.tableDialog.models].remove.msg, '操作提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning',
+                center: true,
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+            }).then(function () {
+                $Request.postJson(that[that.tableDialog.models].remove.url, requestData, function (res) {
+                    if (res.code === 200) {
+                        that.$message({
+                            message: res.message, type: 'success', duration: 2400, onClose: function () {
+                            }
+                        });
+                        that.tablesDialogGetTableList();
+                    } else {
+                        that.$message({
+                            message: res.message, type: 'error', duration: 2400, onClose: function () {
+                            }
+                        });
+                    }
+                })
+            }).catch(function () {
+
+            });
+        },
+
+        tablesDialogRowsStatus: function (model, rows, params) {
+            var that = this;
+
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+
+            if (!that[that.tableDialog.models].status.url || !that[that.tableDialog.models].status.field) {
+                return false;
+            }
+
+            if (!rows[that[that.tableDialog.models].status.field] && rows[that[that.tableDialog.models].status.field] !== 0) {
+                return false;
+            }
+
+            if (!that[that.tableDialog.models].status.maps[rows[that[that.tableDialog.models].status.field]]) {
+                return false;
+            }
+
+            that[that.tableDialog.models].status.msg = '确认' + that[that.tableDialog.models].status.maps[rows[that[that.tableDialog.models].status.field]] + '当前数据吗?';
+
+
+            var requestData = {};
+
+            if (params) {
+                requestData = params;
+            }
+
+            requestData[that[that.tableDialog.models].status.field] = rows[that[that.tableDialog.models].status.field];
+
+            that.$confirm(that[that.tableDialog.models].status.msg, '操作提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning',
+                center: false,
+                dangerouslyUseHTMLString: true,
+                lockScroll: false,
+            }).then(function () {
+                $Request.postJson(that[that.tableDialog.models].status.url, requestData, function (res) {
+                    if (res.code === 200) {
+                        that.$message({
+                            message: res.message, type: 'success', duration: 2400, onClose: function () {
+                            }
+                        });
+                        that.tablesDialogGetTableList();
+                    } else {
+                        that.$message({
+                            message: res.message, type: 'error', duration: 2400, onClose: function () {
+                            }
+                        });
+                    }
+                })
+            }).catch(function () {
+
+            });
+        },
+
+        tablesDialogRowsSort: function (model, rows) {
+            var that = this;
+
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+
+            if (!that[that.tableDialog.models].sort.url) {
+                return false;
+            }
+            var requestData = {};
+            that[that.tableDialog.models].sort.field = that[that.tableDialog.models].sort.field ? that[that.tableDialog.models].sort.field : 'id';
+            that[that.tableDialog.models].sort.item = that[that.tableDialog.models].sort.item ? that[that.tableDialog.models].sort.item : 'sort';
+            if (!rows[that[that.tableDialog.models].sort.field]) {
+                return false;
+            }
+            if (!rows[that[that.tableDialog.models].sort.item]) {
+                return false;
+            }
+            requestData[that[that.tableDialog.models].sort.field] = rows[that[that.tableDialog.models].sort.field];
+            requestData[that[that.tableDialog.models].sort.item] = rows[that[that.tableDialog.models].sort.item];
+            $Request.postJson(that[that.tableDialog.models].sort.url, requestData, function (res) {
+                if (res.code === 200) {
+                    that.$message({message: res.message, type: 'success', duration: 2100});
+                    that.tablesDialogGetTableList();
+                } else {
+                    that.$message({message: res.message, type: 'error', duration: 2100});
+                }
+            })
+        },
+
+        tablesDialogRowsType: function (rows) {
+            var that = this;
+
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+
+            if (!that[that.tableDialog.models].type.url) {
+                return false;
+            }
+            var requestData = {};
+            that[that.tableDialog.models].type.field = that[that.tableDialog.models].type.field ? that[that.tableDialog.models].type.field : 'id';
+            that[that.tableDialog.models].type.item = that[that.tableDialog.models].type.item ? that[that.tableDialog.models].type.item : 'type';
+            if (!rows[that[that.tableDialog.models].type.field]) {
+                return false;
+            }
+            if (!rows[that[that.tableDialog.models].type.item]) {
+                return false;
+            }
+            requestData[that[that.tableDialog.models].type.field] = rows[that[that.tableDialog.models].type.field];
+            requestData[that[that.tableDialog.models].type.item] = rows[that[that.tableDialog.models].type.item];
+            $Request.postJson(that[that.tableDialog.models].type.url, requestData, function (res) {
+                if (res.code === 200) {
+                    that.$message({message: res.message, type: 'success', duration: 2100});
+                    that.tablesDialogGetTableList();
+                } else {
+                    that.$message({message: res.message, type: 'error', duration: 2100});
+                }
+            })
+        },
+
+        tablesDialogSearchEvent: function (model) {
+            var that = this;
+            if (model && typeof model == 'string') that.tableDialog.models = model;
+            that[that.tableDialog.models].pagination.page = 1;
+            that.tablesDialogGetTableList();
+        },
+
+        tablesDialogResetsEvent: function () {},
+    },
+
+    mounted: function () {},
+
+    beforeCreate: function () {},
+
+    created: function () {}
+};
+window.$Utils = {
+    formatDate: function (fmt, time) {
+        time = time ? time * 1000 : (new Date()).getTime();
+        var date = new Date(parseInt(time));
+        var o = {
+            "M+": date.getMonth() + 1,
+            "d+": date.getDate(),
+            "h+": date.getHours(),
+            "m+": date.getMinutes(),
+            "s+": date.getSeconds(),
+            "q+": Math.floor((date.getMonth() + 3) / 3),
+            "S": date.getMilliseconds()
+        };
+        if (/(y+)/.test(fmt))
+            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
+        for (var k in o)
+            if (new RegExp("(" + k + ")").test(fmt))
+                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+        return fmt;
+    },
+
+    /*加密数据*/
+    encrypt: function (str, KEY, IV) {
+        if (!str) return false;
+        KEY = KEY ? KEY : $Public.request.key;
+        IV = IV ? IV : $Public.request.iv;
+        var key = CryptoJS.enc.Utf8.parse(KEY);
+        var iv = CryptoJS.enc.Utf8.parse(IV);
+        var encrypted = CryptoJS.AES.encrypt(str, key, {
+            iv: iv,
+            mode: CryptoJS.mode.CBC,
+            padding: CryptoJS.pad.Pkcs7
+        });
+        return encrypted.toString();
+    },
+
+    /*解密数据*/
+    decrypt: function (str, KEY, IV) {
+        if (!str) return false;
+        KEY = KEY ? KEY : $Public.request.key;
+        IV = IV ? IV : $Public.request.iv;
+
+        var key = CryptoJS.enc.Utf8.parse(KEY);
+        var iv = CryptoJS.enc.Utf8.parse(IV);
+        var decrypted = CryptoJS.AES.decrypt(str, key, {
+            iv: iv,
+            padding: CryptoJS.pad.Pkcs7
+        });
+        return decrypted.toString(CryptoJS.enc.Utf8);
+    },
+    getUrlParams: function (name)
+    {
+        return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ''])[1].replace(/\+/g, '%20')) || null
+    }
+};
+window.$Public = {
+    request: {
+        key: '5B9ADC14C705F1B041DDC2D9B16A2D94',
+        iv: '33092152342590AD',
+        encrypt: true,
+        debug: true,
+    }
+};
+window.$Validator = {
+    json: function (str) {
+        if (typeof str == 'string') {
+            try {
+                var obj = JSON.parse(str);
+                if (typeof obj == 'object' && obj) {
+                    return true;
+                } else {
+                    return false;
+                }
+            } catch (e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    },
+
+    typeOf: function (str, type) {
+        if ((typeof str) === type) {
+            return true;
+        } else {
+            return false;
+        }
+
+    }
+};
+window.$Gallery = {
+    GalleryDialogOpen: function (options) {
+        $App.GalleryParams.options = Object.assign({
+            max: 10,//上传条数
+            size: 20, //上传大小
+            type: '1',//文件类型;1:图片;2:视频;3:音频;4:文件;5:图标;20:网页
+            tabs: false,//是否使用多标签菜单
+            suffix: '', //上传类型
+            multiple: true, //多选
+            file_name: '',
+            callback: function (result) {
+            },
+        }, options);
+        $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+        $Gallery.GalleryUploadInit();
+        $App.GalleryParams.operation.dialog = true;
+    },
+
+    GalleryDialogPages: function (options) {
+        $App.GalleryParams.selected = [];
+        $App.GalleryParams.search.keyword = '';
+        $App.GalleryParams.options = Object.assign({
+            max: 1,//上传条数
+            size: 20, //上传大小
+            type: '1',//文件类型;1:图片;2:视频;3:音频;4:文件;5:图标;20:网页
+            tabs: false,//是否使用多标签菜单
+            suffix: '', //上传类型
+            multiple: false, //多谢
+            callback: function (result) {
+            },
+        }, options);
+        $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+        $Gallery.GalleryUploadInit();
+    },
+
+    GalleryUploadToken: function (callback, type) {
+        type = type ? type : $App.GalleryParams.options.type;
+        $Request.postJson('/admin/framework/common/uploadToken', {type: type}, function (res) {
+            if (res.code === 200) {
+                if ($Validator.typeOf(callback, 'function')) {
+                    callback(res.result);
+                    return true;
+                }
+                if (res.result.driver === "qiniu") {
+                    $App.GalleryParams.driver = res.result.driver;
+                    $App.GalleryParams.action = res.result.action;
+                    $App.GalleryParams.domain = res.result.domain;
+                    $App.GalleryParams.postData.token = res.result.token;
+                    if (res.result.key) {
+                        $App.GalleryParams.postData.key = res.result.key;
+                    }
+                    if (res.result.save_path) {
+                        // TODO
+                    }
+                }
+
+                if (res.result.driver === "oss") {
+                    $App.GalleryParams.driver = res.result.driver;
+                    $App.GalleryParams.action = res.result.ssl + '://' + res.result.domain;
+                    $App.GalleryParams.domain = res.result.ssl + '://' + res.result.domain;
+                    $App.GalleryParams.postData.OSSAccessKeyId = res.result.accessKeyId;
+                    $App.GalleryParams.postData.policy = res.result.policy;
+                    $App.GalleryParams.postData.Signature = res.result.signature;
+                    // $App.GalleryParams.postData['x-oss-security-token'] = res.result.stsToken;
+                    $App.GalleryParams.postData.bucket = res.result.bucket;
+                    $App.GalleryParams.postData.region = res.result.region;
+                    $App.GalleryParams.postData.success_action_status = 200;
+                    if (res.result.save_path) {
+                        // TODO
+                    }
+                }
+
+                if (res.result.driver === "cos"){
+                    // console.log(res.result)
+                    $App.GalleryParams.driver = res.result.driver;
+                    $App.GalleryParams.action = res.result.ssl + '://' + res.result.domain;
+                    $App.GalleryParams.domain = res.result.ssl + '://' + res.result.domain;
+                    $App.GalleryParams.postData.policy = res.result.policy;
+                    $App.GalleryParams.postData.success_action_status = 200;
+                    $App.GalleryParams.postData['q-sign-algorithm'] = res.result.q_sign_algorithm;
+                    $App.GalleryParams.postData['q-ak'] = res.result.q_ak;
+                    $App.GalleryParams.postData['q-key-time'] = res.result.q_key_time;
+                    $App.GalleryParams.postData['q-signature'] = res.result.q_signature;
+                    if (res.result.key) {
+                        $App.GalleryParams.postData.key = res.result.key;
+                    }
+                    if (res.result.save_path) {
+                        // TODO
+                    }
+                }
+
+                if (res.result.driver === 'local') {
+                    $App.GalleryParams.action = '/admin/framework/common/gallery/upload';
+                }
+            } else {
+                callback(false);
+            }
+        })
+    },
+
+    GalleryUploadInit: function () {
+        var that = this;
+        $App.GalleryParams.selected = [];
+        $App.GalleryParams.search.keyword = '';
+        $App.GalleryParams.search.page = 1;
+        $App.GalleryParams.search.size = 12;
+        $App.GalleryParams.options.upload = true;
+        $App.GalleryParams.options.suffix = '';
+        $App.GalleryParams.options.addPage = '';
+        $App.GalleryParams.options.addIcon = '';
+        switch (parseInt($App.GalleryParams.options.type)) {
+            case 1://图片
+                $App.GalleryParams.options.suffix = $App.GalleryParams.options.suffix ?
+                    $App.GalleryParams.options.suffix : 'bmp,gif,jpg,jpeg,png';
+                break;
+            case 2://视频
+                $App.GalleryParams.options.suffix = $App.GalleryParams.options.suffix ?
+                    $App.GalleryParams.options.suffix : 'mp3,wma,avi,rm,rmvb,flv,mpg,mov,mk,mp4';
+                break;
+            case 3://文件
+                $App.GalleryParams.options.suffix = $App.GalleryParams.options.suffix ?
+                    $App.GalleryParams.options.suffix : 'doc,docx,xls,xlsx,xlsm,xlt,csv';
+                break;
+            case 4://网页
+                $App.GalleryParams.options.suffix = '';
+                $App.GalleryParams.options.upload = false;
+                $App.GalleryParams.options.addPage = true;
+                $App.GalleryParams.options.addIcon = false;
+                $App.GalleryParams.search.size = 7;
+                break;
+            case 5://音频
+                break;
+            case 20:
+                $App.GalleryParams.options.suffix = '';
+                $App.GalleryParams.options.upload = false;
+                $App.GalleryParams.options.addIcon = true;
+                $App.GalleryParams.options.addPage = false;
+                break;
+            default:
+        }
+        $App.GalleryParams.search.type = $App.GalleryParams.options.type;
+        $App.GalleryParams.imagesItems = [];
+        $App.GalleryParams.operation.imageTotal = 0;
+        $App.GalleryParams.search.group_id = 0;
+        $Gallery.GalleryUploadParams();
+        $Gallery.GalleryRequestLists();
+    },
+
+    GalleryUploadParams: function () {
+        $App.GalleryParams.postData = {
+            type: $App.GalleryParams.options.type,
+            size: $App.GalleryParams.options.size,
+            suffix: $App.GalleryParams.options.suffix,
+            max: $App.GalleryParams.options.max,
+            group_id: $App.GalleryParams.search.group_id,
+            dir: '',
+            file_name: $App.GalleryParams.options.file_name
+        };
+    },
+
+    GalleryUploadProgress: function (event, file, fileList) {
+        if ($App.GalleryParams.operation.error === false) {
+            $App.GalleryParams.operation.loading = true;
+            $App.GalleryParams.operation.loadingMsg = '文件正在上传 (' + parseFloat((event.percent).toFixed(2)) + '%), 请稍后...';
+        }
+    },
+
+    GalleryUploadSuccess: function (response, file, fileList) {
+        let params = {};
+        // console.log('size:',$App.GalleryParams.size)
+        switch ($App.GalleryParams.driver) {
+            case 'qiniu':
+                response.group_id = $App.GalleryParams.search.group_id;
+                response.type = $App.GalleryParams.search.type;
+                response.code = 200;
+                response.url = $App.GalleryParams.domain + '/' + response.key;
+                response.file_name = $App.GalleryParams.options.file_name;
+                response.size = $App.GalleryParams.size;
+                if (response.code === 200) {
+                    $Request.postJson('/admin/framework/common/gallery/insert', response, function (res) {
+                        if (res.code !== 200) {
+                            $App.$Message(res.message, 'warning');
+                            return true;
+                        }
+                        $App.$Message('文件上传成功!');
+                        $App.GalleryParams.operation.loadingMsg = '';
+                        $App.GalleryParams.operation.loading = false;
+                        $App.$refs.GalleryDialogUpload.clearFiles();
+                        $App.GalleryParams.search.page = 1;
+                        $Gallery.GalleryRequestLists();
+                        $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+                    });
+                }
+                break;
+            case'oss':
+            case'cos':
+                params.group_id = $App.GalleryParams.search.group_id;
+                params.type = $App.GalleryParams.search.type;
+                params.code = 200;
+                params.url = $App.GalleryParams.domain + '/' + $App.GalleryParams.postData.key;
+                params.file_name = $App.GalleryParams.options.file_name;
+                params.size = $App.GalleryParams.size;
+                params.driver = $App.GalleryParams.driver;
+                params.key = $App.GalleryParams.postData.key;
+                if (params.code === 200){
+                    $Request.postJson('/admin/framework/common/gallery/insert', params, function (res) {
+                        if (res.code !== 200) {
+                            $App.$Message(res.message, 'warning');
+                            return true;
+                        }
+                        $App.$Message('文件上传成功!');
+                        $App.GalleryParams.operation.loadingMsg = '';
+                        $App.GalleryParams.operation.loading = false;
+                        $App.$refs.GalleryDialogUpload.clearFiles();
+                        $App.GalleryParams.search.page = 1;
+                        $Gallery.GalleryRequestLists();
+                        $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+                    });
+                }
+                break;
+            // case'cos':
+            //     params.group_id = $App.GalleryParams.search.group_id;
+            //     params.type = $App.GalleryParams.search.type;
+            //     params.code = 200;
+            //     params.url = $App.GalleryParams.domain + '/' + $App.GalleryParams.postData.key;
+            //     params.file_name = $App.GalleryParams.options.file_name;
+            //     params.size = $App.GalleryParams.postData.size;
+            //     params.driver = $App.GalleryParams.driver;
+            //     params.key = $App.GalleryParams.postData.key;
+            //     if (params.code === 200){
+            //         $Request.postJson('/admin/framework/common/gallery/insert', params, function (res) {
+            //             if (res.code !== 200) {
+            //                 $App.$Message(res.message, 'warning');
+            //                 return true;
+            //             }
+            //             $App.$Message('文件上传成功!');
+            //             $App.GalleryParams.operation.loadingMsg = '';
+            //             $App.GalleryParams.operation.loading = false;
+            //             $App.$refs.GalleryDialogUpload.clearFiles();
+            //             $App.GalleryParams.search.page = 1;
+            //             $Gallery.GalleryRequestLists();
+            //             $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+            //         });
+            //     }
+            //     break;
+            default:
+                $App.GalleryParams.operation.loadingMsg = '';
+                $App.GalleryParams.operation.loading = false;
+                $App.$refs.GalleryDialogUpload.clearFiles();
+                if (response.code !== 200) {
+                    $App.$Message(response.message, 'warning');
+                    return true;
+                } else {
+                    $App.$Message('文件上传成功!');
+                    $App.GalleryParams.search.page = 1;
+                    $Gallery.GalleryRequestLists();
+                    break;
+                }
+        }
+    },
+
+    GalleryUploadError: function () {
+        var that = this;
+        $App.$Message('文件上传失败,请重试!', 'warning');
+        $App.GalleryParams.operation.loadingMsg = '';
+        $App.GalleryParams.operation.loading = false;
+        // that.GalleryUploadParams();
+        // $App.$refs.GalleryDialogUpload.clearFiles();
+    },
+
+    GalleryUploadBefore: function (file) {
+        $App.GalleryParams.size = file.size;
+        return new Promise(async (resolve, reject) => {
+            /*验证图片大小*/
+            if ($App.GalleryParams.options.size) {
+                if ((file.size / 1048576) > $App.GalleryParams.options.size) {
+                    $App.$Message('请上传' + $App.GalleryParams.options.size + 'M以内的文件', 'warning');
+                    $Gallery.GalleryCloseOperationLoading();
+                    return reject();
+                }
+            }
+            /*验证文件后缀*/
+            if ($App.GalleryParams.options.suffix) {
+                var args = ((file.name).split('.'));
+                if (args[args.length - 1]) {
+                    var args_suffix = (args[args.length - 1]).toLowerCase();
+                    var suffix = ($App.GalleryParams.options.suffix).split(',');
+                    if ($.inArray(args_suffix, suffix) < 0) {
+                        $App.$Message('请上传' + $App.GalleryParams.options.suffix + '类型的文件', 'warning');
+                        $Gallery.GalleryCloseOperationLoading();
+                        return reject();
+                    }
+                }
+            }
+            $App.GalleryParams.options.file_name = file.name;
+            $App.GalleryParams.postData.file_name = file.name;
+            $App.GalleryParams.operation.loadingMsg = '文件正在上传 (0%), 请稍后...';
+            $App.GalleryParams.operation.loading = true;
+
+            await $Gallery.GalleryGetFileKey().catch(err => {
+                $App.$Message('操作失败!');
+                $Gallery.GalleryCloseOperationLoading();
+                return reject();
+            });
+
+            switch ($App.GalleryParams.driver) {
+                case 'qiniu':
+                    break;
+                case 'oss':
+                    // console.log('oss',$App.GalleryParams.postData);
+                    break;
+                default:
+                    break;
+            }
+
+            $App.GalleryParams.operation.error = false
+            return resolve();
+        })
+    },
+
+    GalleryCloseOperationLoading: function () {
+        setTimeout(function () {
+            $App.$refs.GalleryDialogUpload.clearFiles();
+            $App.GalleryParams.operation.loadingMsg = '';
+            $App.GalleryParams.operation.loading = false;
+            $App.GalleryParams.operation.error = true;
+            $App.GalleryParams.search.page = 1;
+            $Gallery.GalleryRequestLists();
+            $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+        }, 1000)
+    },
+
+    // 获取文件地址
+    GalleryGetFileKey() {
+        return new Promise(function (resolve, reject) {
+            switch ($App.GalleryParams.driver) {
+                case 'qiniu':
+                case 'oss':
+                case 'cos':
+                    $Request.postJson('/admin/framework/common/getFileKey', $App.GalleryParams.postData, function (res) {
+                        if (res.code !== 200) {
+                            $App.$Message(res.message, 'warning');
+                            reject()
+                            return false;
+                        }
+                        $App.GalleryParams.postData.key = res.result.key;
+                        resolve()
+                    });
+                    break;
+                default:
+                    resolve()
+                    return true;
+            }
+        })
+    },
+
+    GalleryUploadDialogClose: function () {
+        $App.GalleryParams.selected = [];
+        $App.GalleryParams.operation.loadingMsg = '';
+        $App.GalleryParams.operation.loading = false;
+        $App.GalleryParams.operation.dialog = false;
+    },
+
+    GalleryUploadDialogSubmit: function () {
+        var that = this;
+        var selected = $App.GalleryParams.selected;
+        if (selected.length <= 0) {
+            $App.$Message('请选择文件!', 'warning');
+            return false;
+        }
+        if (!$App.GalleryParams.options.multiple) {
+            selected = selected[0];
+        }
+
+        $App.GalleryParams.options.callback(selected);
+        $App.GalleryParams.selected = [];
+        $App.GalleryParams.operation.loading = false;
+        $App.GalleryParams.operation.dialog = false;
+    },
+
+    GalleryGroupChangeEvent: function (item) {
+        $.each($App.GalleryParams.groupItems, function (key, val) {
+            val.active = false;
+        });
+        item.active = true;
+        $App.GalleryParams.imagesItems = [];
+        $App.GalleryParams.search.page = 1;
+        $App.GalleryParams.operation.imageTotal = 0;
+        $App.GalleryParams.search.group_id = item.id;
+        $Gallery.GalleryRequestLists();
+    },
+
+    GalleryGroupRemoveEvent: function (index, item) {
+        $App.$Confirm('确认删除当前分组吗?', function (res) {
+            $Request.postJson('/admin/framework/common/gallery/groupRemove', {
+                id: item.id
+            }, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: res.message, type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                } else {
+                    $App.$message({message: res.message, type: 'error', duration: 2400});
+                }
+            });
+        });
+    },
+
+    GalleryRemotePictureEvent: function () {
+        var that = this;
+        $App.GalleryParams.operation.loading = true;
+        $App.$prompt('', '图片地址', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            inputValue: '',
+            lockScroll: false,
+            inputPlaceholder: '请输入图片地址',
+            inputValidator: function (e) {
+                return $Validator.image(e);
+            },
+            inputErrorMessage: '请输入图片地址',
+        }).then(function (result) {
+
+            if (!result.value) {
+                $App.$message({type: 'error', message: '请输入图片地址!'});
+                return false;
+            }
+            $App.GalleryParams.postData._value = result.value;
+            $Request.postJson('/admin/framework/common/gallery/remote', $App.GalleryParams.postData, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: '图片保存成功!', type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                    that.GalleryUploadParams();
+                } else {
+                    $App.$message({message: res.message, type: 'error', duration: 2400});
+                }
+                $App.GalleryParams.operation.loading = false;
+            });
+        }).catch(function () {
+            $App.GalleryParams.operation.loading = false;
+        });
+    },
+
+    GalleryAddPageEvent: function (item, is_update) {
+        var params = {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            lockScroll: false,
+            inputPlaceholder: '网页地址规则:网页名称,网页地址',
+            inputErrorMessage: '请输入图片地址',
+        };
+        if (is_update && item.id) {
+            params.inputValue = item.original + ',' + item.url;
+        }
+        $App.$prompt('', '网页地址', params).then(function (result) {
+            if (!result.value) {
+                $App.$message({type: 'error', message: '请输入网页地址!'});
+                return false;
+            }
+            $App.GalleryParams.postData._value = result.value;
+            if (is_update && item.id) {
+                $App.GalleryParams.postData._id = item.id;
+                $App.GalleryParams.postData._is_update = 1;
+            }
+            $App.GalleryParams.postData._value = result.value;
+            $Request.postJson('/admin/framework/common/gallery/pages', $App.GalleryParams.postData, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: res.message, type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                } else {
+                    $App.$message({message: res.message, type: 'error', duration: 2400});
+                }
+            });
+        }).catch(function () {
+        });
+    },
+
+    GalleryItemUpdateOriginalEvent: function (item) {
+        $App.$prompt('', '修改文件名', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            inputPlaceholder: '请输入文件名',
+            inputValue: item.original,
+            lockScroll: false,
+            closeOnClickModal: false,
+        }).then(function (params) {
+            if (!params.value) {
+                $App.$message({message: '请输入文件名!', type: 'error', duration: 2400});
+            } else {
+                $Request.postJson('/admin/framework/common/gallery/original', {
+                    id: item.id, name: params.value
+                }, function (res) {
+                    if (res.code === 200) {
+                        $App.$message({message: '文件名修改成功!', type: 'success', duration: 2400});
+                        $Gallery.GalleryRequestLists();
+                    } else {
+                        $App.$message({message: '文件名修改失败,请稍后再试!', type: 'error', duration: 2400});
+                    }
+                })
+            }
+        }).catch(function () {
+        });
+    },
+
+    GalleryItemRemoveEvent: function (item) {
+        $App.$confirm('确认删除当前数据吗?删除后不可恢复!', '操作提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+            dangerouslyUseHTMLString: true,
+            lockScroll: false,
+            center: true
+        }).then(function () {
+            $Request.postJson('/admin/framework/common/gallery/remove', {
+                id: item.id
+            }, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: '文件删除成功!', type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                } else {
+                    $App.$message({message: '文件删除失败,请稍后再试!', type: 'error', duration: 2400});
+                }
+            })
+        }).catch(function () {
+        });
+    },
+
+    GalleryTabEvent: function () {
+        $Gallery.GalleryUploadToken($App.GalleryParams.options.type);
+        $Gallery.GalleryUploadInit();
+    },
+
+    GalleryGroupUpdateEvent: function (index, item) {
+        $App.$prompt('', '修改分组', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            inputValue: item.name,
+            lockScroll: false,
+            inputPlaceholder: '请输入分组名称',
+            inputValidator: function (e) {
+                return (e && e.length < 10) ? true : false;
+            },
+            inputErrorMessage: '请输入分组名称',
+        }).then(function (result) {
+            if (!result.value) {
+                $App.$message({type: 'error', message: '请输入分组名称!'});
+                return false;
+            }
+            $Request.postJson('/admin/framework/common/gallery/groupUpdate', {
+                id: item.id,
+                name: result.value
+            }, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: res.message, type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                } else {
+                    $App.$message({message: res.message, type: 'error', duration: 2400});
+                }
+            });
+        }).catch(function () {
+        });
+    },
+
+    GalleryGroupInsertEvent: function () {
+        if ($App.GalleryParams.groupItems.length > 6) {
+            $App.$message({message: '分组最多可添加5个!', type: 'error', duration: 2400});
+            return false;
+        }
+        $App.$prompt('', '添加分组', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            lockScroll: false,
+            inputPlaceholder: '请输入分组名称,最长10个字符',
+            inputValidator: function (e) {
+                return (e && e.length < 10) ? true : false;
+            },
+            inputErrorMessage: '请输入分组名称',
+        }).then(function (result) {
+            if (!result.value) {
+                $App.$message({type: 'error', message: '请输入分组名称!'});
+                return false;
+            }
+            $Request.postJson('/admin/framework/common/gallery/groupCreate', {
+                name: result.value,
+                type: $App.GalleryParams.options.type
+            }, function (res) {
+                if (res.code === 200) {
+                    $App.$message({message: res.message, type: 'success', duration: 2400});
+                    $Gallery.GalleryRequestLists();
+                } else {
+                    $App.$message({message: res.message, type: 'error', duration: 2400});
+                }
+            });
+        }).catch(function () {
+        });
+    },
+
+    GalleryGroupManageEvent: function () {
+        $App.GalleryParams.operation.groupManage = !$App.GalleryParams.operation.groupManage;
+    },
+
+    GalleryImagesPageChange: function (page) {
+        var that = this;
+        $App.GalleryParams.search.page = page;
+        $Gallery.GalleryRequestLists();
+    },
+
+    GalleryItemCheckboxEvent: function (item) {
+        var that = this;
+        // console.log(11111,item);
+        if (item.active === 0 || item.active === false) {
+            /*多选*/
+            if ($App.GalleryParams.options.max > 1) {
+                if ($App.GalleryParams.selected.length >= $App.GalleryParams.options.max) {
+                    $App.$message({
+                        message: '最多可选择' + $App.GalleryParams.options.max + '项!',
+                        type: 'warning'
+                    });
+                    return true;
+                } else {
+                    item.active = true;
+                    $App.GalleryParams.selected.push(item);
+                }
+            } else {
+                if ($App.GalleryParams.selected.length > 0) {
+                    $App.GalleryParams.selected.forEach(function (selected_item) {
+                        $App.GalleryParams.imagesItems.forEach(function (rows, index) {
+                            if (selected_item.id === rows.id) {
+                                rows.active = false;
+                            }
+                        });
+                    });
+                }
+                item.active = true;
+                $App.GalleryParams.selected = [];
+                $App.GalleryParams.selected[0] = item;
+            }
+        } else {
+            $Gallery.GalleryItemActiveInEvent(item);
+        }
+    },
+
+    GalleryItemActiveInEvent: function (item) {
+        /*取消选中*/
+        if ($App.GalleryParams.options.max > 1) {
+            if ($App.GalleryParams.selected.length > 0) {
+                $App.GalleryParams.selected.forEach(function (rows, index) {
+                    if (rows.id === item.id) {
+                        $App.GalleryParams.selected.splice(index, 1);
+                        item.active = false;
+                        return true;
+                    }
+                });
+            } else {
+                item.active = false;
+                $App.GalleryParams.selected = [];
+                return true;
+            }
+        } else {
+            item.active = false;
+            $App.GalleryParams.selected = [];
+            return true;
+        }
+    },
+
+    GalleryItemDropdownEvent: function (e, item) {
+        var that = this;
+        if (e.target.dataset.command === 'edit') {
+            that.GalleryItemUpdateOriginalEvent(item);
+        } else {
+            that.GalleryItemRemoveEvent(item);
+        }
+    },
+
+    GalleryRequestLists: function () {
+        $App.GalleryParams.operation.loading = true;
+        $App.GalleryParams.operation.groupManage = false;
+        $Gallery.GalleryUploadParams();
+        $Gallery.GalleryGroupRequestLists();
+        $Request.postJson('/admin/framework/common/gallery/iframe', $App.GalleryParams.search, function (res) {
+            if (res.code === 200) {
+                $App.GalleryParams.imagesItems = res.result.data;
+                $App.GalleryParams.operation.imageTotal = res.result.total;
+                $App.GalleryParams.selected.forEach(function (selected_item) {
+                    $App.GalleryParams.imagesItems.forEach(function (item, index) {
+                        if (selected_item.id === item.id) {
+                            item.active = true;
+                        }
+                    });
+                });
+            }
+            $App.GalleryParams.operation.loadingMsg = '';
+            $App.GalleryParams.operation.loading = false;
+            $App.layouts.dialogFormsHeight = {
+                'max-height': parseInt((document.documentElement.clientHeight * 0.75) - 120) + 'px'
+            };
+            // console.log($App.layouts.dialogFormsHeight)
+        });
+    },
+
+    GalleryGroupRequestLists: function () {
+        $App.GalleryParams.loading = true;
+        $Request.postJson('/admin/framework/common/gallery/group', $App.GalleryParams.search, function (res) {
+            if (res.code === 200) {
+                $App.GalleryParams.groupItems = res.result;
+            }
+        });
+    },
+};
+window.$Center = {
+    CenterDialogOpen: function () {
+        $App.CenterParams.loadingMsg = '正在加载数据,请稍后...';
+        $App.CenterParams.loading = true;
+        $App.CenterParams.dialog = true;
+        $App.CenterParams.model = {name:'',account:'',password:''};
+        $Request.postJson('/admin/framework/common/center/info', {}, function (res) {
+            if(res.code === 200){
+                $App.CenterParams.model = res.result;
+                $App.CenterParams.loading = false;
+            } else {
+                $App.$message({message: res.message, type: 'error'});
+                $App.CenterParams.loadingMsg = res.message;
+            }
+        })
+    },
+    CenterDialogClose: function () {
+        $App.CenterParams.dialog = false;
+    },
+    CenterDialogSubmits: function (){
+        $App.CenterParams.loadingMsg = '正在提交,请稍后...';
+        $App.CenterParams.loading = true;
+        var params = $App.CenterParams.model;
+        $Request.postJson('/admin/framework/common/center/update', params, function (res) {
+            if(res['code'] === 200) {
+                $App.$Message(res['message'], function () {
+                    $App.CenterParams.loading = false;
+                    $App.CenterParams.dialog = false;
+                    location.reload();
+                });
+            } else {
+                $App.$Message(res.message, 'error');
+            }
+        });
+    },
+    // 监测抽屉鼠标事件
+    handleWrapperMousedown(e) {
+        // 如果为true,则表示点击发生在遮罩层
+        $App.CenterParams.dialogClassModel = !!e.target.classList.contains('el-dialog__wrapper')
+    },
+    handleWrapperMouseup(e) {
+        if ((!!e.target.classList.contains('el-dialog__wrapper')) && $App.CenterParams.dialogClassModel) {
+            $App.CenterParams.dialog = false;
+        }
+    },
+    // 监测抽屉鼠标事件 End.
+};
+window.$Arrays = {
+    /*  arrayLookup(data,'id',1,'name');*/
+    arrayLookup: function (data, key, value, targetKey) {
+        if (!data) return '---';
+        var data_length = data.length;
+        var targetValue = "";
+        for (var i = 0; i < data_length; i++) {
+            if (!data[i][key]) {
+                break;
+            }
+            if (data[i][key] == value) {
+                targetValue = targetKey ? data[i][targetKey] : data[i];
+                break;
+            }
+        }
+        return targetValue ? targetValue : '---';
+    }
+};
+
+// 自定义模板
+Vue.component('va-media', {
+    props: {
+        size: {type: Number, default: 20},
+        file: {type: String, default: ''},
+        width:{ type: String, default: '400px'},
+        height:{ type: String, default: '240px'}
+    },
+
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+    template: '<div style="border: 1px dashed #2d8cf0;border-radius: 5px;cursor: pointer" :style="{\'width\':width,\'height\':height}" @click="pictureGalleryOpen">' +
+        '<img src="/statics/v1/image/empty/data.png" style="width: 100%;height: 100%;object-fit: contain;" v-if="!file">' +
+        '<video :src="file" :poster="file+\'?vframe/jpg/offset/2/w/130/h/140/\'" ' +
+        'controls="controls" width="100%" height="100%" autoplay v-if="file">' +
+        '<source :src="file" type="video/mp4" /></video></div>',
+    methods: {
+        pictureGalleryOpen: function() {
+            var that = this;
+            $Gallery.GalleryDialogOpen({
+                max: 1,
+                size: that.size,
+                multiple: false,
+                type: 2,
+                cat:true,
+                callback: function(res) {
+                    that.$emit('change', res.url);
+                }
+            });
+        }
+    },
+    mounted: function() {
+
+    }
+});
+Vue.component('va-image', {
+    props: {
+        size: {type: Number, default: 20},
+        src: {type: String, default: ''},
+        key: {type: String, default: ''}
+    },
+    data: function () {
+        return {
+            imageUrl: '',
+            imageUrlList: [],
+        };
+    },
+    watch: {
+        src(value) {
+            if (!this.imageUrl) {
+                this._init(value);
+            }
+        },
+    },
+    template: '<el-image class="tables-image" :src="imageUrl" fit="contain" lazy :size="size" :key="key" :preview-src-list="imageUrlList">' +
+        '<div slot="error" class="image-slot"><i class="fa fa-picture-o"></i></div>' +
+        '</el-image>',
+    methods: {
+        _init: function (value) {
+            var that = this;
+            if (!value) {
+                that.imageUrl = '/statics/v1/image/common/empty.jpeg';
+                return true;
+            }
+            if ($Validator.json(value)) {
+                var fileItems = JSON.parse(value);
+                if (fileItems.length && fileItems.length > 0) {
+                    $.each(fileItems, function (key, item) {
+                        that.imageUrlList.push(item.url);
+                    });
+                    that.imageUrl = that.imageUrlList[0];
+                } else {
+                    that.imageUrl = fileItems.url;
+                }
+            } else {
+                if (value.includes('base64')){
+                    that.imageUrlList = [value];
+                }else {
+                    that.imageUrlList = value.split(",").filter(function (n) {
+                        return n
+                    });
+                }
+                if (that.imageUrlList.length < 1) {
+                    that.imageUrl = '/statics/v1/image/common/empty.jpeg';
+                } else {
+                    that.imageUrl = that.imageUrlList[0];
+                }
+            }
+        }
+    },
+    mounted: function () {
+        this._init(this.src);
+    }
+});
+Vue.component('va-forms-tips', {
+    props: {},
+    data: function () {
+        return {};
+    },
+    template: '<span class="Va-help-block" data-7512a93d><i class="el-icon-info"></i>  <slot></slot></span>',
+    mounted: function () {
+
+    }
+});
+Vue.component("va-picture", {
+    props: {
+        action: {
+            type: String,
+            default: '/admin/framework/common/pictureUploads'
+        },
+        size: {
+            type: Number,
+            default: 20
+        },
+        suffix: {
+            type: String,
+            default: 'png,bmp,jpeg,jpg,gif'
+        },
+        postData: {
+            type: Object,
+            default: {}
+        },
+        file: {
+            type: String,
+            default: ''
+        },
+        gallery: {
+            type: Boolean,
+            default: true
+        },
+        alt: {
+            type: Boolean,
+            default: false
+        },
+        name: {
+            type: Boolean,
+            default: false
+        },
+        disabled: {
+            type: Boolean,
+            default: false
+        },
+        onSuccess: {
+            type: Function,
+            default: function (res) {
+            }
+        },
+
+    },
+
+    data: function () {
+        return {
+            picture: {
+                postHeaders: {
+                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+                },
+                uploadStatus: false,
+                progress: 0,
+            },
+            fileItems: {
+                url: '',
+                alt: '',
+                name: ''
+            },
+            _fileName: '', _fileSize: 0,
+            galleryOptions: {},
+            uploadOption: {driver: 'local', action: '', token: '', domain: ''},
+        }
+    },
+
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+    computed: {
+        fileItemsAlt() {
+            return this.fileItems.alt;
+        },
+        fileItemsName() {
+            return this.fileItems.name;
+        }
+    },
+    watch: {
+        file(value) {
+            var that = this;
+
+            if (that.alt || that.name) {
+                if ($Validator.json(value)) {
+                    that.fileItems = JSON.parse(value);
+                }
+            } else {
+                that.fileItems = {
+                    url: value,
+                    alt: '',
+                    name: ''
+                };
+            }
+        },
+
+        fileItemsAlt(value) {
+            this.emitItemsEvent()
+        },
+        fileItemsName(value) {
+            this.emitItemsEvent()
+        },
+    },
+
+    template: '<div v-if="!fileItems.url" :disabled="disabled">\n' +
+        '  <el-upload\n' +
+        '          :action="action"\n' +
+        '          :show-file-list="false"\n' +
+        '          :headers="picture.postHeaders"\n' +
+        '          :data="postData"\n' +
+        '          :on-success="pictureUploadSuccess"\n' +
+        '          :on-progress="pictureUploadProgress"\n' +
+        '          :on-change="pictureChangeEvent"\n' +
+        '          :on-error="pictureUploadError"\n' +
+        '          ref="pictureUploadRef"\n' +
+        '          :disabled="disabled"\n' +
+        '          :before-upload="pictureUploadBefore" v-if="!gallery">\n' +
+        '      <div class="va-component-picture" :disabled="disabled" v-if="!picture.uploadStatus">\n' +
+        '          <div class="upload" :disabled="disabled">\n' +
+        '              <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '          </div>\n' +
+        '      </div>\n' +
+        '      <div class="va-component-picture" v-else :disabled="disabled">\n' +
+        '          <el-progress type="circle" :percentage="picture.progress" style="margin-top: 5px;" ></el-progress>\n' +
+        '      </div>\n' +
+        '  </el-upload>\n' +
+        '  <div v-else class="va-component-picture gallery" :disabled="disabled" @click="pictureGalleryOpen">\n' +
+        '      <div class="upload" :disabled="disabled">\n' +
+        '          <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '      </div>\n' +
+        '  </div>\n' +
+        '</div>\n' +
+        '<div class="va-component-picture" v-else :disabled="disabled">\n' +
+        '    <div class="show" :title="fileItems.alt">\n' +
+        '        <el-image class="image" :src="fileItems.url"></el-image>\n' +
+        '        <div class="shadow" v-if="!disabled">\n' +
+        '            <i class="el-icon-delete icon" @click="pictureItemsRemove(fileItems)"></i>\n' +
+        '            <el-dropdown class= "dropdown-picture-edit" placement="top" size="mini" style="position:absolute" @command="pictureItemsEdit(event)" v-if="alt || name">\n' +
+        '               <span class="el-dropdown-link"><i class="el-icon-edit icon"></i> </span>\n' +
+        '             <el-dropdown-menu slot="dropdown">\n' +
+        '               <el-dropdown-item command="name" data-command="name" v-if="name">名称</el-dropdown-item>\n' +
+        '               <el-dropdown-item command="alt" data-command="alt" v-if="alt">alt</el-dropdown-item>\n' +
+        '  </el-dropdown-menu></el-dropdown>\n' +
+        '        </div>\n' +
+        '    </div>\n' +
+        '</div>',
+    methods: {
+        pictureGalleryOpen: function () {
+            var that = this;
+            if (that.disabled) {
+                return false;
+            }
+            $Gallery.GalleryDialogOpen({
+                max: 1,
+                size: that.size,
+                suffix: that.suffix,
+                multiple: false,
+                type: '1',
+                tabs: false,
+                callback: function (res) {
+                    that.fileItems = {url: res.url, alt: res.original, name: res.original};
+                    that.emitItemsEvent();
+                    that.picture.uploadStatus = false;
+                    that.picture.progress = 0;
+                }
+            });
+        },
+
+        pictureItemsEdit: function (e, item, index) {
+            var that = this;
+            if (that.disabled) {
+                return false;
+            }
+            var tips = (e.target.dataset.command === 'name') ? '名称' : 'alt';
+            $App.$prompt('', '修改图片' + tips, {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                inputPlaceholder: '请输入图片' + tips,
+                inputValue: that.fileItems[e.target.dataset.command],
+                lockScroll: false,
+            }).then(function (params) {
+                if (!params.value) {
+                    $App.$message({
+                        message: '请输入图片' + tips,
+                        type: 'error',
+                        duration: 2400
+                    });
+                } else {
+                    that.fileItems[e.target.dataset.command] = params.value;
+                    that.emitItemsEvent();
+                }
+            }).catch(function () {
+            });
+            return true;
+        },
+
+        pictureItemsRemove: function () {
+            var that = this;
+            that.fileItems = {
+                url: '',
+                alt: '',
+                name: ''
+            };
+            that.emitItemsEvent();
+        },
+
+        pictureAltEvent: function (items, index) {
+            var that = this;
+            that.$refs[('picturePopoverAlt00101')].doClose();
+        },
+
+        pictureUploadProgress: function (event, file, fileList) {
+            var that = this;
+            that.picture.progress = parseFloat((event.percent).toFixed(2));
+        },
+
+        pictureUploadSuccess: function (response, file, fileList) {
+            var that = this;
+            var url;
+            that.$refs.pictureUploadRef.clearFiles();
+            if (response.code !== 200) {
+                switch (that.uploadOption.driver) {
+                    case 'qiniu':
+                        response.url = that.uploadOption.domain + '/' + response.key;
+                        url = response.url;
+                        that.onSuccess(response);
+                        break;
+                    case'oss':
+                    default:
+                        url = response.result.url;
+                        $App.$Message(response.msg, 'warning');
+                        that.picture.uploadStatus = false;
+                        that.picture.progress = 0;
+                        break;
+                }
+                that.fileItems = {
+                    url: url,
+                    alt: that.fileItems.alt,
+                    name: that.fileItems.name,
+                    defaultImg: that.uploadOption.defaultImg
+                };
+                that.emitItemsEvent();
+                $App.$Message('文件上传成功!', 'success');
+                that.picture.uploadStatus = false;
+                that.picture.progress = 0;
+                return true;
+            } else {
+                $App.$Message(response.msg, 'warning');
+                that.picture.uploadStatus = false;
+                that.picture.progress = 0;
+            }
+        },
+
+        pictureUploadError: function () {
+            var that = this;
+            that.picture.uploadStatus = false;
+            that.picture.progress = 0;
+            $App.$Message('文件上传失败,请重试!', 'warning');
+            that.$refs.pictureUploadRef.clearFiles();
+            return true;
+        },
+
+        pictureUploadBefore: function (file, e) {
+            var that = this;
+            /*验证图片大小*/
+            if (that.size) {
+                if ((file.size / 1048576) > that.size) {
+                    $App.$Message('请上传' + that.size + 'M以内的文件', 'warning');
+                    that.$refs.pictureUploadRef.clearFiles();
+                    return false;
+                }
+            }
+
+            /*验证文件后缀*/
+            if (that.suffix) {
+                var args = ((file.name).split('.'));
+                if (args[args.length - 1]) {
+                    var suffix = (that.suffix).split(',');
+                    if ($.inArray((args[args.length - 1]).toLowerCase(), suffix) < 0) {
+                        $App.$Message('请上传' + that.suffix + '类型的文件', 'warning');
+                        that.$refs.pictureUploadRef.clearFiles();
+                        return false;
+                    }
+                }
+            }
+            that._fileSize = (file.size / 1048576).toFixed(2);
+            that._fileName = file.name;
+            that.picture.uploadStatus = true;
+            that.picture.progress = 1;
+            return true;
+        },
+
+        emitItemsEvent: function () {
+            var that = this;
+            if (that.alt || that.name) {
+                that.$emit('change', JSON.stringify(that.fileItems));
+            } else {
+                that.$emit('change', that.fileItems.url);
+            }
+            that.UploadToken();
+        },
+
+        UploadToken: function () {
+            var that = this;
+            if (that.gallery) return true;
+            $Gallery.GalleryUploadToken(function (res) {
+                that.uploadOption.driver = res.result.driver;
+                that.uploadOption.domain = res.result.domain;
+                that.action = res.result.action;
+                that.postData.token = res.result.token;
+                if (res.result.key) {
+                    $App.postData.key = res.result.key;
+                }
+                if (res.result.driver === 'local') {
+                    $App.action = '/admin/framework/common/pictureUploads';
+                }
+            }, 1)
+        }
+    },
+
+    mounted: function () {
+        var that = this;
+        that.UploadToken();
+        if (!that.size) {
+            that.postData.size = 20;
+        } else {
+            that.postData.size = that.size;
+        }
+        if (!that.suffix) {
+            that.postData.suffix = 'png,bmp,jpeg,jpg,gif';
+        } else {
+            that.postData.suffix = that.suffix;
+        }
+        if (that.alt) {
+            if (that.file) {
+                if ((typeof that.file) == 'object') {
+                    that.fileItems = that.file;
+                } else {
+                    if (!$Validator.json(that.file)) {
+                        console.error('va-picture components. File parameter requires a JSON string');
+                    } else {
+                        that.fileItems = JSON.parse(that.file);
+                    }
+                }
+            } else {
+                that.fileItems = {
+                    url: '',
+                    alt: ''
+                };
+            }
+        } else {
+            that.fileItems = {
+                url: (that.file && that.file != 'null') ? that.file : '',
+                alt: '',
+                name: ''
+            };
+        }
+
+        that.galleryOptions = {
+            max: 1,
+            size: that.size,
+            suffix: that.suffix,
+            type: 'image',
+            callback: 'pictureSelectedSuccess'
+        };
+        that.picture.uploadStatus = false;
+        that.picture.progress = 0;
+    }
+});
+Vue.component("va-picture-multiple", {
+    props: {
+        action: {
+            type: String,
+            default: '/admin/framework/common/pictureUploads'
+        },
+        size: {
+            type: Number,
+            default: 20
+        },
+        suffix: {
+            type: String,
+            default: 'png,bmp,jpeg,jpg,gif'
+        },
+        postData: {
+            type: Object,
+            default: {}
+        },
+        limit: {
+            type: Number,
+            default: 10
+        },
+        file: {
+            type: String,
+            default: ''
+        },
+        gallery: {
+            type: Boolean,
+            default: true
+        },
+        alt: {
+            type: Boolean,
+            default: false
+        },
+        name: {
+            type: Boolean,
+            default: false
+        },
+        disabled: {
+            type: Boolean,
+            default: false
+        },
+    },
+
+    data: function () {
+        return {
+            picture: {
+                postHeaders: {
+                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+                },
+                uploadStatus: false,
+                progress: 0,
+            },
+            fileItems: [],
+            galleryOptions: {},
+            uploadOption: {driver: 'local', action: '', token: '', domain: ''},
+        }
+    },
+
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+
+    watch: {
+        file(value) {
+            if (this.fileItems && this.fileItems.length > 0) {
+                return true;
+            }
+            this.formatFileEvent(value);
+        }
+    },
+    template: '<div class="va-component-picture-multiple" :disabled="disabled" id="_va-component-picture">\n' +
+        '    <template v-if="fileItems.length > 0" >\n' +
+
+        '           <div v-for="(item, index) in fileItems" class="va-component-picture picture__Sortable" :data-no="index" :disabled="disabled">\n' +
+        '               <div class="show" :title="item.alt">\n' +
+        '                   <img class="image" :src="item.url">\n' +
+        '                       <div class="shadow" v-if="!disabled">\n' +
+        '                           <i class="el-icon-delete icon" @click="pictureItemsRemove(item, index)"></i>\n' +
+        '                               <el-dropdown class= "dropdown-picture-edit" placement="top" style="position:absolute" size="mini" @command="pictureItemsEdit(event, item, index)" v-if="alt || name">\n' +
+        '                                   <span class="el-dropdown-link"><i class="el-icon-edit icon"></i> </span>\n' +
+        '                                   <el-dropdown-menu slot="dropdown">\n' +
+        '                                       <el-dropdown-item command="name" data-command="name" v-if="name">名称</el-dropdown-item>\n' +
+        '                                       <el-dropdown-item command="alt" data-command="alt" v-if="alt">alt</el-dropdown-item>\n' +
+        '                                   </el-dropdown-menu>' +
+        '                               </el-dropdown>\n' +
+        '                       </div>\n' +
+        '                   </div>\n' +
+        '           </div>' +
+
+        '    </template>\n' +
+        '    <template v-if="fileItems.length < limit">\n' +
+        '        <el-upload\n' +
+        '                :action="action"\n' +
+        '                :show-file-list="false"\n' +
+        '                :headers="picture.postHeaders"\n' +
+        '                :data="postData"\n' +
+        '                :multiple="true"\n' +
+        '                :limit="limit"\n' +
+        '                :on-success="pictureUploadSuccess"\n' +
+        '                :on-progress="pictureUploadProgress"\n' +
+        '                :on-error="pictureUploadError"\n' +
+        '                ref="pictureMultipleUploadRef"\n' +
+        '                :before-upload="pictureUploadBefore" v-if="!gallery">\n' +
+        '            <div class="va-component-picture" :disabled="disabled" v-if="!picture.uploadStatus" >\n' +
+        '                <div class="upload" :disabled="disabled">\n' +
+        '                    <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '                </div>\n' +
+        '            </div>\n' +
+        '            <div class="va-component-picture" :disabled="disabled" v-else>\n' +
+        '                <el-progress type="circle" :percentage="picture.progress" style="margin-top: 10px;" ></el-progress>\n' +
+        '            </div>\n' +
+        '        </el-upload>\n' +
+        '        <div v-else class="va-component-picture gallery" :disabled="disabled" @click="pictureGalleryOpen">\n' +
+        '            <div class="upload" :disabled="disabled">\n' +
+        '                <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </template>\n' +
+        '</div>',
+
+    methods: {
+        pictureGalleryOpen: function () {
+            var that = this;
+            if (that.disabled) {
+                return false;
+            }
+            $Gallery.GalleryDialogOpen({
+                max: (that.limit - that.fileItems.length),
+                size: that.size,
+                suffix: that.suffix,
+                multiple: true,
+                type: '1',
+                tabs: false,
+                callback: function (res) {
+                    res.forEach(function (item, key) {
+                        if (that.fileItems.length < 1) {
+                            that.fileItems.push({url: item.url, alt: item.original, name: item.original});
+                        } else {
+                            if (that.fileItems.length < that.limit) {
+                                that.fileItems.push({url: item.url, alt: item.original, name: item.original});
+                            }
+                        }
+                    });
+                    that.emitItemsEvent();
+                    that.picture.uploadStatus = false;
+                    that.picture.progress = 0;
+                }
+            });
+        },
+
+        pictureItemsEdit: function (e, item, index) {
+            var that = this;
+            if (that.disabled) {
+                return false;
+            }
+            var tips = (e.target.dataset.command === 'name') ? '名称' : 'alt';
+            $App.$prompt('', '修改图片' + tips, {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                inputPlaceholder: '请输入图片' + tips,
+                inputValue: item[e.target.dataset.command],
+                lockScroll: false,
+            }).then(function (params) {
+                if (!params.value) {
+                    $App.$message({
+                        message: '请输入图片' + tips,
+                        type: 'error',
+                        duration: 2400
+                    });
+                } else {
+                    item[e.target.dataset.command] = params.value;
+                    that.emitItemsEvent();
+                }
+            }).catch(function(){});
+            return true;
+        },
+        pictureItemsRemove: function (items, index) {
+            var that = this;
+            that.fileItems.splice(index, 1);
+            that.emitItemsEvent();
+        },
+        pictureUploadProgress: function (event, file, fileList) {
+            var that = this;
+            that.picture.progress = parseFloat((event.percent).toFixed(2));
+        },
+        pictureUploadSuccess: function (response, file, fileList) {
+            var that = this;
+            var fileItemsMaps = that.fileItems;
+            var url;
+            switch (that.uploadOption.driver) {
+                case 'qiniu':
+                    url = that.uploadOption.domain + '/' + response.key;
+                    break;
+                case'oss':
+                default:
+                    if (response.code !== 200) {
+                        $App.$Message(response.msg, 'warning');
+                        that.picture.uploadStatus = false;
+                        that.picture.progress = 0;
+                        return true;
+                    } else {
+                        url = response.result.url;
+                    }
+                    break;
+            }
+            if (fileItemsMaps.length < that.limit) {
+                fileItemsMaps.push({url: url, alt: '', name: ''});
+            }
+            ;
+            that.fileItems = fileItemsMaps;
+            that.emitItemsEvent();
+            $App.$Message('文件上传成功!', 'success');
+            that.picture.uploadStatus = false;
+            that.picture.progress = 0;
+            return true;
+        },
+
+        pictureUploadError: function () {
+            var that = this;
+            that.picture.uploadStatus = false;
+            that.picture.progress = 0;
+            $App.$Message('文件上传失败,请重试!', 'warning');
+            that.$refs.pictureMultipleUploadRef.clearFiles();
+            return true;
+        },
+        pictureUploadBefore: function (file, e) {
+            var that = this;
+            that.UploadToken();
+            /*验证图片大小*/
+            if (that.size) {
+                if ((file.size / 1048576) > that.size) {
+                    $App.$Message('请上传' + that.size + 'M以内的文件', 'warning');
+                    that.$refs.pictureMultipleUploadRef.clearFiles();
+                    return false;
+                }
+            }
+
+            /*验证文件后缀*/
+            if (that.suffix) {
+                var args = ((file.name).split('.'));
+                if (args[args.length - 1]) {
+                    var suffix = (that.suffix).split(',');
+                    if ($.inArray((args[args.length - 1]).toLowerCase(), suffix) < 0) {
+                        $App.$Message('请上传' + that.suffix + '类型的文件', 'warning');
+                        that.$refs.pictureMultipleUploadRef.clearFiles();
+                        return false;
+                    }
+                }
+            }
+            that.picture.uploadStatus = true;
+            that.picture.progress = 1;
+            return true;
+        },
+        emitItemsEvent: function () {
+            var that = this;
+            that.UploadToken();
+            if (that.alt || that.name) {
+                that.$emit('change', JSON.stringify(that.fileItems));
+                that.SortTableEvent();
+            } else {
+                var fileItems = '';
+                if (that.fileItems.length > 0) {
+                    that.fileItems.forEach(function (item, key) {
+                        if (key === that.fileItems.length) {
+                            fileItems += item.url;
+                        } else {
+                            fileItems += item.url + ',';
+                        }
+                    });
+                    that.SortTableEvent();
+                }
+                that.$emit('change', fileItems);
+            }
+        },
+
+        formatFileEvent: function () {
+            var that = this;
+            if (that.alt || that.name) {
+                if (that.file) {
+                    if ((typeof that.file) == 'object') {
+                        that.fileItems = that.file;
+                    } else {
+                        if (!$Validator.json(that.file)) {
+                            console.info('va-picture-multiple components. File parameter requires a JSON string');
+                        } else {
+                            that.fileItems = JSON.parse(that.file);
+                            that.emitItemsEvent();
+                        }
+                    }
+                } else {
+                    that.fileItems = [];
+                }
+            } else {
+                if (!that.file || that.file == '[]' || that.file == '{}') {
+                    that.fileItems = [];
+                } else {
+                    if (that.file) {
+                        var fileItems = (that.file).split(',');
+
+                        if (fileItems && fileItems.length > 0) {
+                            for (var i = 0; i <= fileItems.length; i++) {
+                                if (fileItems[i]) {
+                                    that.fileItems.push({
+                                        url: fileItems[i],
+                                        alt: ''
+                                    });
+                                }
+                            }
+                            that.emitItemsEvent();
+                        } else {
+                            that.fileItems = [];
+                        }
+                    } else {
+                        that.fileItems = [];
+                    }
+                }
+            }
+        },
+
+        UploadToken: function () {
+            var that = this;
+            if (that.gallery) return true;
+
+            $Gallery.GalleryUploadToken(function (res) {
+                that.uploadOption.driver = res.driver;
+                that.uploadOption.domain = res.domain;
+                that.action = res.action;
+                that.postData.token = res.token;
+                if (res.key) {
+                    that.postData.key = res.key;
+                }
+                if (res.driver === 'local') {
+                    that.action = '/admin/framework/common/pictureUploads';
+                }
+            }, 1);
+        },
+
+        SortTableEvent: function () {
+            //获取对象
+            var that = this;
+            var el = document.getElementById('_va-component-picture');
+            //设置配置
+            var ops = {
+                animation: 1000,
+                dataIdAttr: "data-no",
+                draggable: ".picture__Sortable",
+                //拖动结束
+                onEnd: function (evt) {
+                    var asd = [];
+                    var sortableArr = sortable.toArray();
+                    $.each(sortableArr, function (key, val) {
+                        asd.push(that.fileItems[val]);
+                    });
+                    that.fileItems = asd;
+                    that.emitItemsEvent();
+                },
+            };
+            //初始化
+            var sortable = Sortable.create(el, ops);
+
+        }
+    },
+
+    mounted: function () {
+        var that = this;
+        that.UploadToken();
+        if (!that.size) {
+            that.postData.size = 20;
+        } else {
+            that.postData.size = that.size;
+        }
+        if (!that.suffix) {
+            that.postData.suffix = 'png,bmp,jpeg,jpg,gif';
+        } else {
+            that.postData.suffix = that.suffix;
+        }
+
+        that.formatFileEvent();
+
+        that.galleryOptions = {
+            max: that.limit,
+            size: that.size,
+            suffix: that.suffix,
+            type: 'image',
+            callback: 'pictureSelectedSuccess'
+        };
+        that.picture.uploadStatus = false;
+        that.picture.progress = 0;
+    }
+});
+Vue.component("va-video", {
+    props: {
+        action: {
+            type: String,
+            default: '/admin/framework/common/fileUploads'
+        },
+        size: {
+            type: Number,
+            default: 20
+        },
+        suffix: {
+            type: String,
+            default: 'mp3,wma,avi,rm,rmvb,flv,mpg,mov,mk,mp4'
+        },
+        postData: {
+            type: Object,
+            default: {
+                size: 20,
+                suffix: 'mp3,wma,avi,rm,rmvb,flv,mpg,mov,mk,mp4'
+            }
+        },
+        file: {
+            type: String,
+            default: "{url:'', size:'', original:''}"
+        },
+        gallery: {
+            type: Boolean,
+            default: true
+        },
+        preview: {
+            type: Boolean,
+            default: false
+        },
+        disabled: {
+            type: String,
+            default: false
+        },
+        onSuccess: {
+            type: String,
+            default: ''
+        },
+    },
+
+    data: function () {
+        return {
+            postHeaders: {
+                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+            },
+            uploadOption: {driver: 'local', domain: ''},
+            uploadStatus: false,
+            _fileName: '',
+            _fileSize: 0,
+            percentage: 0,
+            fileItems: {url: '', size: '', original: ''},
+            galleryOptions: {}
+        }
+    },
+
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+
+    watch: {
+        file(value) {
+            if (!this.fileItems.url) {
+                this.fileItems = JSON.parse(value);
+                this.$emit('change', JSON.stringify(this.fileItems));
+            }
+        }
+    },
+    template: '<div class="va-component-file" :disabled="disabled">\n' +
+        '    <el-upload\n' +
+        '            v-if="!fileItems.url && !uploadStatus && !gallery"\n' +
+        '            :action="action"\n' +
+        '            :headers="postHeaders"\n' +
+        '            limit="1"  drag\n' +
+        '            :show-file-list="false"\n' +
+        '            :data="postData"\n' +
+        '            :disabled="disabled"\n' +
+        '            :on-progress="fileUploadProgress"\n' +
+        '            :on-success="fileUploadSuccess"\n' +
+        '            :on-error="fileUploadError"\n' +
+        '            :before-upload="fileUploadBefore"\n' +
+        '            ref="fileDialogUpload"\n' +
+        '    >\n' +
+        '        <div class="upload">\n' +
+        '            <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '            <div class="el-upload__text" style="margin-top: -12px">\n' +
+        '                <el-link type="primary" :underline="false">\n' +
+        '                    <span style="font-weight: 500;font-size: 15px">点击视频上传</span>\n' +
+        '                </el-link>\n' +
+        '                <div style="font-size: 12px;margin-top:-15px">\n' +
+        '                    <div style="color: #909399;height: 15px">视频大小{{size}}MB以内</div>\n' +
+        '                    <div style="color: #909399;height: 15px">支持类型:{{suffix}}</div>\n' +
+        '                </div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </el-upload>\n' +
+        '    <div class="upload" @click="fileGalleryOpen" v-if="!fileItems.url && !uploadStatus && gallery">\n' +
+        '        <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '        <div class="el-upload__text" style="margin-top: -12px">\n' +
+        '            <el-link type="primary" :disabled="disabled" :underline="false">\n' +
+        '                <span style="font-weight: 500;font-size: 15px">点击视频上传</span>\n' +
+        '            </el-link>\n' +
+        '            <div style="font-size: 12px;margin-top:-15px">\n' +
+        '                <div style="color: #909399;margin-top: 0">视频大小{{size}}MB以内</div>\n' +
+        '                <div style="color: #909399;margin-top: -20px">支持类型:{{suffix}}</div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </div>\n' +
+        '\n' +
+        '    <div class="progress" v-if="uploadStatus && percentage > 0">\n' +
+        '        <el-progress type="circle" :percentage="percentage" color=" var(--themeColors)"></el-progress>\n' +
+        '    </div>\n' +
+        '\n' +
+        '    <div class="files" v-if="fileItems.url && !uploadStatus">\n' +
+        '        <el-button  :disabled="disabled" class="Va-button button" size="mini" type="default" @click="fileUploadAgain">重新上传</el-button>\n' +
+        '        <el-button  :disabled="disabled" class="Va-button button" size="mini" v-if="preview" type="default" @click="fileUploadPreview" style="top:42px">预览视频</el-button>\n' +
+        '        <i class="el-icon-document icon"></i>\n' +
+        '        <div class="text">\n' +
+        '            <span class="text-space" style="font-weight: 500;font-size: 15px;line-height: 20px;display: inline-block;width: 90%;margin-top:10px">{{fileItems.original}}</span>\n' +
+        '            <div style="font-size: 12px;margin-top: -20px">\n' +
+        '                <div class="el-upload__tip" slot="tip" style="color: #909399">视频大小:{{fileItems.size}}字节</div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </div>\n' +
+        '</div>',
+    methods: {
+        fileGalleryOpen: function () {
+            var that = this;
+            $Gallery.GalleryDialogOpen({
+                max: 1,
+                size: that.size,
+                suffix: that.suffix,
+                multiple: false,
+                type: '2',
+                tabs: false,
+                callback: function (res) {
+                    that.emitItemsEvent(res);
+                    $App.$Message('视频上传成功!', 'success');
+                    that.uploadStatus = false;
+                    that.percentage = 0;
+                }
+            });
+        },
+
+        fileUploadPreview: function () {
+            var that = this;
+            $Preview.PreviewDialogOpen(that.fileItems.url);
+        },
+
+        fileUploadAgain: function () {
+            var that = this;
+            that.fileItems = {url: '', size: '', original: ''};
+            that.emitItemsEvent({url: '', size: '', original: ''});
+            that.uploadStatus = false;
+            that.percentage = 0;
+            if (that.onSuccess) {
+                that.onSuccess();
+            }
+        },
+
+        fileUploadProgress: function (event) {
+            var that = this;
+            that.percentage = parseFloat((event.percent).toFixed(2));
+        },
+
+        fileUploadSuccess: function (response, file, fileList) {
+            var that = this;
+            var _result = {url: '', original: '', size: '', code: 200};
+            switch (that.uploadOption.driver) {
+                case 'qiniu':
+                    _result.url = that.uploadOption.domain + '/' + response.key;
+                    _result.original = that._fileName;
+                    _result.size = that._fileSize;
+                    that.percentage = 0;
+                    that.uploadStatus = false;
+                    that.emitItemsEvent(_result);
+                    if (that.onsuccess) {
+                        that.onsuccess(_result);
+                    }
+                    $App.$Message('视频上传成功!', 'success');
+                    break;
+                case'oss':
+                default:
+                    if (response.code !== 200) {
+                        that.percentage = 0;
+                        that.uploadStatus = false;
+                        $App.$Message(response.msg, 'warning');
+                        return true;
+                    } else {
+                        that.percentage = 0;
+                        that.uploadStatus = false;
+                        that.emitItemsEvent(response.result);
+                        if (that.onsuccess) {
+                            that.onsuccess(response.result);
+                        }
+                        $App.$Message('视频上传成功!', 'success');
+                        return true;
+                    }
+            }
+        },
+
+        fileUploadError: function () {
+            var that = this;
+            that.percentage = 0;
+            that.uploadStatus = false;
+            $App.$Message('视频上传失败,请重试!', 'warning');
+            that.$refs.fileDialogUpload.clearFiles();
+            return true;
+        },
+
+        fileUploadBefore: function (file, e) {
+            var that = this;
+            /*验证图片大小*/
+            if (that.size) {
+                if ((file.size / 1048576) > that.size) {
+                    $App.$Message('请上传' + that.size + 'M以内的视频', 'warning');
+                    that.$refs.fileDialogUpload.clearFiles();
+                    return false;
+                }
+            }
+            /*验证视频后缀*/
+            if (that.suffix) {
+                var args = ((file.name).split('.'));
+
+                if (args[args.length - 1]) {
+                    var suffix = (that.suffix).split(',');
+                    if ($.inArray(args[args.length - 1], suffix) < 0) {
+                        $App.$Message('请上传' + that.suffix + '类型的视频', 'warning');
+                        that.$refs.fileDialogUpload.clearFiles();
+                        return false;
+                    }
+                }
+            }
+            that._fileSize = (file.size / 1048576).toFixed(2);
+            that._fileName = file.name;
+            that.percentage = 1;
+            that.uploadStatus = true;
+            return true;
+        },
+
+        emitItemsEvent: function (value) {
+            var that = this;
+            that.fileItems = {
+                url: value.url,
+                size: value.size,
+                original: value.original
+            };
+            that.UploadToken();
+            that.$emit('change', JSON.stringify(that.fileItems));
+        },
+        UploadToken: function () {
+            var that = this;
+            if (that.gallery) return true;
+
+            $Gallery.GalleryUploadToken(function (res) {
+                that.uploadOption.driver = res.driver;
+                that.uploadOption.domain = res.domain;
+                that.action = res.action;
+                that.postData.token = res.token;
+                if (res.key) {
+                    that.postData.key = res.key;
+                }
+                if (res.driver === 'local') {
+                    that.action = '/admin/framework/common/fileUploads';
+                }
+            }, 3);
+
+        }
+    },
+
+    mounted: function () {
+        var that = this;
+        that.UploadToken();
+        that.postData.size = that.size ? that.size : 20;
+        that.postData.suffix = that.suffix ? that.suffix : 'doc,docx,xls,xlsx,xlsm,xlt,csv';
+        if (that.file) {
+            if ((typeof that.file) == 'object') {
+                that.fileItems = that.file;
+                that.$emit('change', JSON.stringify(that.fileItems));
+            } else {
+                if (!$Validator.json(that.file)) {
+                    console.error('va-file components. File parameter requires a JSON string');
+                } else {
+                    that.fileItems = JSON.parse(that.file);
+                    that.$emit('change', JSON.stringify(that.fileItems));
+                }
+            }
+        } else {
+            that.fileItems = {
+                url: '',
+                size: '',
+                original: ''
+            };
+            that.$emit('change', JSON.stringify(that.fileItems));
+        }
+        that.uploadStatus = false;
+        that.percentage = 0;
+    }
+});
+Vue.component("va-file", {
+    props: {
+        action: {
+            type: String,
+            default: '/admin/framework/common/fileUploads'
+        },
+        size: {
+            type: Number,
+            default: 20
+        },
+        suffix: {
+            type: String,
+            default: 'doc,docx,xls,xlsx,xlsm,xlt,csv'
+        },
+        postData: {
+            type: Object,
+            default: {
+                size: 20,
+                suffix: 'doc,docx,xls,xlsx,xlsm,xlt,csv'
+            }
+        },
+        file: {
+            type: String,
+            default: "{url:'', size:'', original:''}"
+        },
+        gallery: {
+            type: Boolean,
+            default: true
+        },
+        preview: {
+            type: Boolean,
+            default: false
+        },
+        disabled: {
+            type: String,
+            default: false
+        },
+        onSuccess: {
+            type: String,
+            default: ''
+        },
+    },
+
+    data: function () {
+        return {
+            postHeaders: {
+                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+            },
+            uploadOption: {driver: 'local', domain: ''},
+            uploadStatus: false,
+            _fileName: '',
+            _fileSize: 0,
+            percentage: 0,
+            fileItems: {url: '', size: '', original: ''},
+            galleryOptions: {}
+        }
+    },
+
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+
+    watch: {
+        file(value) {
+            if (!this.fileItems.url) {
+                this.fileItems = JSON.parse(value);
+                this.$emit('change', JSON.stringify(this.fileItems));
+            }
+        }
+    },
+    template: '<div class="va-component-file" :disabled="disabled">\n' +
+        '    <el-upload\n' +
+        '            v-if="!fileItems.url && !uploadStatus && !gallery"\n' +
+        '            :action="action"\n' +
+        '            :headers="postHeaders"\n' +
+        '            limit="1"  drag\n' +
+        '            :show-file-list="false"\n' +
+        '            :data="postData"\n' +
+        '            :disabled="disabled"\n' +
+        '            :on-progress="fileUploadProgress"\n' +
+        '            :on-success="fileUploadSuccess"\n' +
+        '            :on-error="fileUploadError"\n' +
+        '            :before-upload="fileUploadBefore"\n' +
+        '            ref="fileDialogUpload"\n' +
+        '    >\n' +
+        '        <div class="upload">\n' +
+        '            <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '            <div class="el-upload__text" style="margin-top: -12px">\n' +
+        '                <el-link type="primary" :underline="false">\n' +
+        '                    <span style="font-weight: 500;font-size: 15px">点击文件上传</span>\n' +
+        '                </el-link>\n' +
+        '                <div style="font-size: 12px;margin-top:-15px">\n' +
+        '                    <div style="color: #909399;height: 15px">文件大小{{size}}MB以内</div>\n' +
+        '                    <div style="color: #909399;height: 15px">支持类型:{{suffix}}</div>\n' +
+        '                </div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </el-upload>\n' +
+        '    <div class="upload" @click="fileGalleryOpen" v-if="!fileItems.url && !uploadStatus && gallery">\n' +
+        '        <i class="el-icon-upload icon" :disabled="disabled"></i>\n' +
+        '        <div class="el-upload__text" style="margin-top: -12px">\n' +
+        '            <el-link type="primary" :disabled="disabled" :underline="false">\n' +
+        '                <span style="font-weight: 500;font-size: 15px">点击文件上传</span>\n' +
+        '            </el-link>\n' +
+        '            <div style="font-size: 12px;margin-top:-15px">\n' +
+        '                <div style="color: #909399;margin-top: 0">文件大小{{size}}MB以内</div>\n' +
+        '                <div style="color: #909399;margin-top: -20px">支持类型:{{suffix}}</div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </div>\n' +
+        '\n' +
+        '    <div class="progress" v-if="uploadStatus && percentage > 0">\n' +
+        '        <el-progress type="circle" :percentage="percentage" color=" var(--themeColors)"></el-progress>\n' +
+        '    </div>\n' +
+        '\n' +
+        '    <div class="files" v-if="fileItems.url && !uploadStatus">\n' +
+        '        <el-button  :disabled="disabled" class="Va-button button" size="mini" type="default" @click="fileUploadAgain">重新上传</el-button>\n' +
+        '        <el-button  :disabled="disabled" class="Va-button button" size="mini" v-if="preview" type="default" @click="fileUploadPreview" style="top:42px">预览文件</el-button>\n' +
+        '        <i class="el-icon-document icon"></i>\n' +
+        '        <div class="text">\n' +
+        '            <span style="font-weight: 500;font-size: 15px;line-height: 20px;display: inline-block;width: 90%;margin-top:10px">{{fileItems.original}}</span>\n' +
+        '            <div style="font-size: 12px;margin-top: -20px">\n' +
+        '                <div class="el-upload__tip" slot="tip" style="color: #909399">文件大小:{{fileItems.size}}字节</div>\n' +
+        '            </div>\n' +
+        '        </div>\n' +
+        '    </div>\n' +
+        '</div>',
+    methods: {
+        fileGalleryOpen: function () {
+            var that = this;
+            $Gallery.GalleryDialogOpen({
+                max: 1,
+                size: that.size,
+                suffix: that.suffix,
+                multiple: false,
+                type: '3',
+                tabs: false,
+                callback: function (res) {
+                    that.emitItemsEvent(res);
+                    $App.$Message('文件上传成功!', 'success');
+                    that.uploadStatus = false;
+                    that.percentage = 0;
+                }
+            });
+        },
+
+        fileUploadPreview: function () {
+            var that = this;
+            $Preview.PreviewDialogOpen(that.fileItems.url);
+        },
+
+        fileUploadAgain: function () {
+            var that = this;
+            that.fileItems = {url: '', size: '', original: ''};
+            that.emitItemsEvent({url: '', size: '', original: ''});
+            that.uploadStatus = false;
+            that.percentage = 0;
+            if (that.onSuccess) {
+                that.onSuccess();
+            }
+        },
+
+        fileUploadProgress: function (event) {
+            var that = this;
+            that.percentage = parseFloat((event.percent).toFixed(2));
+        },
+
+        fileUploadSuccess: function (response, file, fileList) {
+            var that = this;
+            var _result = {url: '', original: '', size: '', code: 200};
+            switch (that.uploadOption.driver) {
+                case 'qiniu':
+                    _result.url = that.uploadOption.domain + '/' + response.key;
+                    _result.original = that._fileName;
+                    _result.size = that._fileSize;
+                    that.percentage = 0;
+                    that.uploadStatus = false;
+                    that.emitItemsEvent(_result);
+                    if (that.onsuccess) {
+                        that.onsuccess(_result);
+                    }
+                    $App.$Message('文件上传成功!', 'success');
+                    break;
+                case'oss':
+                default:
+                    if (response.code !== 200) {
+                        that.percentage = 0;
+                        that.uploadStatus = false;
+                        $App.$Message(response.msg, 'warning');
+                        return true;
+                    } else {
+                        that.percentage = 0;
+                        that.uploadStatus = false;
+                        that.emitItemsEvent(response.result);
+                        if (that.onsuccess) {
+                            that.onsuccess(response.result);
+                        }
+                        $App.$Message('文件上传成功!', 'success');
+                        return true;
+                    }
+            }
+        },
+
+        fileUploadError: function () {
+            var that = this;
+            that.percentage = 0;
+            that.uploadStatus = false;
+            $App.$Message('文件上传失败,请重试!', 'warning');
+            that.$refs.fileDialogUpload.clearFiles();
+            return true;
+        },
+
+        fileUploadBefore: function (file, e) {
+            var that = this;
+            /*验证图片大小*/
+            if (that.size) {
+                if ((file.size / 1048576) > that.size) {
+                    $App.$Message('请上传' + that.size + 'M以内的文件', 'warning');
+                    that.$refs.fileDialogUpload.clearFiles();
+                    return false;
+                }
+            }
+            /*验证文件后缀*/
+            if (that.suffix) {
+                var args = ((file.name).split('.'));
+
+                if (args[args.length - 1]) {
+                    var suffix = (that.suffix).split(',');
+                    if ($.inArray(args[args.length - 1], suffix) < 0) {
+                        $App.$Message('请上传' + that.suffix + '类型的文件', 'warning');
+                        that.$refs.fileDialogUpload.clearFiles();
+                        return false;
+                    }
+                }
+            }
+            that._fileSize = (file.size / 1048576).toFixed(2);
+            that._fileName = file.name;
+            that.percentage = 1;
+            that.uploadStatus = true;
+            return true;
+        },
+
+        emitItemsEvent: function (value) {
+            var that = this;
+            that.fileItems = {
+                url: value.url,
+                size: value.size,
+                original: value.original
+            };
+            that.UploadToken();
+            that.$emit('change', JSON.stringify(that.fileItems));
+        },
+        UploadToken: function () {
+            var that = this;
+            if (that.gallery) return true;
+
+            $Gallery.GalleryUploadToken(function (res) {
+                that.uploadOption.driver = res.driver;
+                that.uploadOption.domain = res.domain;
+                that.action = res.action;
+                that.postData.token = res.token;
+                if (res.key) {
+                    that.postData.key = res.key;
+                }
+                if (res.driver === 'local') {
+                    that.action = '/admin/framework/common/fileUploads';
+                }
+            }, 3);
+
+        }
+    },
+
+    mounted: function () {
+        var that = this;
+        that.UploadToken();
+        that.postData.size = that.size ? that.size : 20;
+        that.postData.suffix = that.suffix ? that.suffix : 'doc,docx,xls,xlsx,xlsm,xlt,csv';
+        if (that.file) {
+            if ((typeof that.file) == 'object') {
+                that.fileItems = that.file;
+                that.$emit('change', JSON.stringify(that.fileItems));
+            } else {
+                if (!$Validator.json(that.file)) {
+                    console.error('va-file components. File parameter requires a JSON string');
+                } else {
+                    that.fileItems = JSON.parse(that.file);
+                    that.$emit('change', JSON.stringify(that.fileItems));
+                }
+            }
+        } else {
+            that.fileItems = {
+                url: '',
+                size: '',
+                original: ''
+            };
+            that.$emit('change', JSON.stringify(that.fileItems));
+        }
+        that.uploadStatus = false;
+        that.percentage = 0;
+    }
+});
+/*弹窗时需要销毁 va-editor; 最好是同弹窗一起v-if*/
+Vue.component("va-editor", {
+    props: {
+        height: {
+            type: String,
+            default: '200'
+        },
+        max_height: {
+            type: String,
+            default: '500'
+        },
+        id: {
+            type: String,
+            default: $Request.random(12)
+        },
+        placeholder: {
+            type: String,
+            default: '请填写内容'
+        },
+        disabled: {
+            type: String,
+            default: false
+        },
+        content: {
+            type: String,
+            default: ''
+        },
+        inline: {
+            type: Boolean,
+            default: false
+        },
+        toolbar: {
+            type: String,
+            default: '#fixed-editor-util'
+        },
+        mode: {
+            type: String,
+            default: 'ordinary'
+        }, //simple, ordinary ,complex
+        is_news: {
+            type: String,
+            default: '0'
+        },
+    },
+
+    data: function () {
+        return {
+            vaEditorObj: {},
+            reloadNum: 5,
+        }
+    },
+
+    model: {
+        prop: 'content',
+        event: 'change'
+    },
+
+    watch: {
+        content(value) {
+            var that = this;
+            // if (!that.vaEditorObj.getContent({
+            //     format: 'text'
+            // }) && value) {
+            //     that.vaEditorObj.setContent(value);
+            // }
+            return true;
+        },
+    },
+    template: '<div :id="id" class="va-editor tinymce-editor-ele" style="opacity: 0;width: 0;height: 0"></div>',
+    methods: {
+        createEditor: function () {
+            var that = this;
+            var plugins, toolbar = '';
+            that.mode = that.mode ? that.mode : 'ordinary';
+            switch (that.mode) {
+                /*emoticons*/
+                case 'simple':
+                    plugins = 'print autosave preview searchreplace autolink directionality visualblocks visualchars fullscreen gallery image  link code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern emoticons bdmap autoresize toolbarsticky';//media
+                    toolbar = 'code undo redo | removeformat formats fontselect fontsizeselect bold italic underline  strikethrough hr blockquote forecolor backcolor  | gallery table  \
+                  //| alignleft aligncenter alignright alignjustify outdent indent indent2em lineheight ';//image media imagetools
+                    break;
+                case 'ordinary':
+                    plugins = 'print autosave preview searchreplace autolink directionality visualblocks visualchars fullscreen gallery link code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern emoticons bdmap autoresize toolbarsticky';//media
+                    toolbar = 'code undo redo | removeformat formats fontselect fontsizeselect bold italic underline  strikethrough hr blockquote forecolor backcolor \
+                  //| alignleft aligncenter alignright alignjustify outdent indent indent2em lineheight | gallery';//media
+                    break;
+                case 'complex':
+                    plugins = '';
+                    toolbar = '';
+                    break;
+            }
+            $(function () {
+                tinymce.init({
+                    selector: '#' + that.id,
+                    resize: true,
+                    language: 'zh_CN',
+                    menubar: that.mode === 'simple' ? false : ' file edit view table insert tool format image',
+                    inline: that.inline,
+                    font_formats: "微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings",
+                    toolbar_groups: {
+                        textformat: {
+                            text: '文字格式',
+                            icon: 'text-color',
+                            tooltip: 'Formatting',
+                            items: 'forecolor backcolor bold italic underline strikethrough',
+                        },
+                        paragraph: {
+                            text: '段落',
+                            icon: 'align-left',
+                            tooltip: 'alignment',
+                            items: 'alignleft aligncenter alignright alignjustify outdent indent indent2em lineheight',
+                        },
+                        alignments: {
+                            text: '对齐方式',
+                            icon: 'align-left',
+                            tooltip: 'alignment',
+                            items: 'alignleft aligncenter alignright alignjustify outdent indent indent2em lineheight ',
+                        },
+                    },
+                    plugins: plugins,
+                    toolbar: toolbar,
+                    //                 plugins: 'print autosave preview searchreplace autolink directionality visualblocks visualchars fullscreen image media link code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern emoticons bdmap autoresize ',//autosave
+                    //                 toolbar: 'preview fullscreen code undo redo restoredraft  | textformat | paragraph | styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
+                    // table  emoticons hr  | powerpaste',
+                    //                 plugins: 'print autosave preview searchreplace autolink directionality visualblocks visualchars fullscreen image media link code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern emoticons bdmap autoresize ',//autosave
+                    //                 toolbar: 'code undo redo restoredraft formatting | forecolor backcolor bold italic underline strikethrough | alignleft aligncenter alignright alignjustify outdent indent  | \
+                    // styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
+                    // table  emoticons hr  | powerpaste',
+                    placeholder: that.placeholder ? that.placeholder : '请输入内容',
+                    readonly: that.disabled, //只读模式
+                    branding: false, //隐藏右下角技术支持
+                    statusbar: false,
+                    elementpath: false, //隐藏底栏的元素路径
+                    custom_undo_redo_levels: 30, //撤销次数
+                    object_resizing: true, //调整大小控件开关
+                    contextmenu_never_use_native: false, //在编辑器中屏蔽浏览器本身的右键菜单
+                    fixed_toolbar_container: that.inline ? that.toolbar : '', // '#fixed-editor-util',//指定工具栏在某一容器顶部固定。
+                    // fixed_toolbar_container: '#va-editor-content',//指定工具栏在某一容器顶部固定。
+                    custom_ui_selector: 'body',
+                    toolbar_mode: 'wrap',
+                    // toolbar_sticky: true,
+                    cfyun_toolbar_sticky: true,
+                    toolbar_sticky_type: false,
+                    toolbar_sticky_elem_height: 60,
+                    toolbar_sticky_wrap: '.Va-container',
+
+                    fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
+                    remove_trailing_brs: true, //删除最尾的br
+                    width: '100%',
+                    min_height: parseInt(that.height),
+                    autoresize_bottom_margin: 50, //自动调整编辑器大小的方法以适应内容
+                    //autoresize_overflow_padding: 50,//指定编辑器body初始化时两侧的距离,相当于padding-left加padding-right
+                    max_height: parseInt(that.max_height),
+                    autolink: true, //autolink插件会自动创建超链接
+                    fullscreen_native: true, //全屏将不在是网页全屏,而是使用浏览器的全屏模式
+                    /*图片参数*/
+                    image_uploadtab: true, //配置了images_upload_url后会在图像对话框中添加“上传”标签用于上传本地图像,此选项设false可关闭该标签。
+                    image_advtab: true, //为图像属性编辑窗口添加高级属性
+                    automatic_uploads: false, //Data URL/Blob URL插入图片和文件到内容区的方式
+                    images_upload_credentials: true,
+                    file_picker_types: 'image media',
+                    images_upload_url: '/admin/framework/common/uploadEditor',
+                    autosave_ask_before_unload: false, //当关闭或跳转URL时,弹出提示框提醒用户仍未保存变更内容。
+                    autosave_interval: '5s', //自动存稿的世界间隔。注意该值为字符串,以秒为单位
+                    convert_urls: false, //上传文件自动转换相对路径
+                    image_caption: true, //在弹出框中增加一个“标题”选项,开启后图片将被包含在figure(HTML5新增)内。
+                    image_description: true, //为img添加属性alt
+                    typeahead_urls: true, //设false就是关闭地址input的自动完成。
+                    media_alt_source: false, //显示隐藏资源备用地址输入框
+                    media_poster: false, //显示隐藏图片封面输入框
+                    media_live_embeds: true,
+                    hidden_input: false,
+                    visual: false,
+                    inline_boundaries: false,
+                    auto_focus: false,
+                    setup: function (editor) {
+                        that.vaEditorObj = editor;
+                        editor.on('input change undo redo execCommand KeyUp', function (e) {
+                            $(".el-container.is-vertical").css({
+                                flexDirection: 'inherit'
+                            });
+                            $(".el-container.is-vertical").css({
+                                flexDirection: 'column'
+                            });
+                            that.$emit('change', editor.getContent());
+                        });
+                        that.vaEditorObj.setMode(that.disabled ? 'readonly' : 'design');
+                    },
+                    init_instance_callback: function (editor) {
+                        setTimeout(function () {
+                            that.vaEditorObj.setContent(that.content);
+                        }, 100);
+                        //that.vaEditorObj.focus();
+                    },
+
+                    handle_event_callback: function (event) {
+                        that.vaEditorObj.focus();
+                    },
+                    audio_template_callback: function (data) {
+                        return '<audio controls>' + '\n<source src="' + data.source1 + '"' + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' + '</audio>';
+                    },
+                    /*文件上传回调*/
+                    file_picker_callback: function (callback, value, meta) {
+                        window.galleryObj = {};
+                        var fileParams = {
+                            ts: meta.filetype,
+                            ft: 1,
+                            is_news: that.is_news,
+                            mx: 1,
+                            ck: 'ComponentPictureTemporaryEvent',
+                            se: 20,
+                        };
+                        switch (meta.filetype) {
+                            case "image":
+                                fileParams.ft = 1;
+                                fileParams.mx = 1;
+                                fileParams.se = 20;
+                                break;
+                            case "media":
+                                fileParams.ft = 2;
+                                fileParams.mx = 1;
+                                fileParams.se = 100;
+                                break;
+                            case "file":
+                                fileParams.ft = 3;
+                                fileParams.mx = 1;
+                                fileParams.se = 100;
+                                break;
+                            default:
+                                break;
+                        }
+                        $Gallery.GalleryDialogOpen({
+                            max: fileParams.mx,
+                            size: fileParams.se,
+                            is_new: fileParams.is_news,
+                            multiple: false,
+                            type: fileParams.ft,
+                            callback: function (res) {
+                                callback(res.url, {
+                                    source2: res.url,
+                                    poster: res.original
+                                });
+                            }
+                        });
+                    },
+                });
+            });
+            if (!that.vaEditorObj.id && that.reloadNum > 0) {
+                setTimeout(function () {
+                    that.createEditor();
+                    that.reloadNum = that.reloadNum - 1;
+                }, 500);
+            }
+        }
+    },
+
+    beforeDestroy: function () {
+        tinymce.remove();
+    },
+
+    beforeCreate: function () {
+    },
+
+    created: function () {
+        var that = this;
+        setTimeout(function () {
+            that.createEditor()
+        }, 100);
+    },
+
+    mounted: function () {
+    }
+});
+Vue.component('va-timer', {
+    props: {
+        time: {type: Number, default: 0},
+    },
+    data: function () {
+        return {
+            flag:null,
+            hour:0,
+            minute:0,
+            second:0,
+            hour_time:'00',
+            minute_time:'00',
+            second_time:'00',
+        }
+    },
+    model: {
+        prop: 'file',
+        event: 'change'
+    },
+    template: '<div style="display: inline">' +
+        '<span>{{hour_time}}</span>' +
+        '<span>:</span>' +
+        '<span>{{minute_time}}</span>' +
+        '<span>:</span>' +
+        '<span>{{second_time}}</span>' +
+        '</div>',
+    methods: {
+        start(time){
+            var that = this;
+
+            if (time > 0){
+                // 初始化时间
+                var nowTime = Date.now()
+                var date = new Date(parseInt(nowTime - (time * 1000)))
+                that.hour = date.getUTCHours();
+                that.minute = date.getUTCMinutes();
+                that.second = date.getUTCSeconds();
+            }
+
+            // 开始定时
+            that.flag = setInterval(()=>{
+                that.second += 1;
+                if(that.second >= 60){
+                    that.second = 0;
+                    that.minute += 1;
+                }
+
+                if (that.minute >= 60){
+                    that.minute = 0;
+                    that.hour += 1;
+                }
+
+                that.hour_time = that.zeroize(that.hour);
+                that.minute_time = that.zeroize(that.minute);
+                that.second_time = that.zeroize(that.second);
+            },1000)
+        },
+        zeroize(n){
+            return n < 10 ? '0' + n : "" + n;
+        }
+    },
+    mounted: function() {
+        var that = this;
+        that.start(that.time);
+    }
+});
+// Other
+$(function () {
+    // document.getElementsByClassName('el-drawer__container').onclick = function () {
+    $('body').on('mousedown', '.el-drawer__container', function (e) {
+        // $DrawerForms.methods.handleWrapperMousedown(e);
+    })
+    $('body').on('mouseup', '.el-drawer__container', function (e) {
+        // $DrawerForms.methods.handleWrapperMouseup(e);
+    })
+
+    $('body').on('mousedown', '.el-dialog__wrapper', function (e) {
+        // $DialogForms.methods.handleWrapperMousedown(e);
+    })
+    $('body').on('mouseup', '.el-dialog__wrapper', function (e) {
+        // $DialogForms.methods.handleWrapperMouseup(e);
+    })
+
+    /**
+     * panda
+     * 页面加载进度条
+     */
+    if (location.hostname.match(/ricostacruz\.com$/)) {
+        var _gaq = _gaq || [];
+        _gaq.push(["_setAccount", "UA-20473929-1"]), _gaq.push(["_trackPageview"]), function () {
+            var a = document.createElement("script");
+            a.type = "text/javascript", a.async = !0, a.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
+            var b = document.getElementsByTagName("script")[0];
+            b.parentNode.insertBefore(a, b)
+        }()
+    }
+    $('body').show();
+    $('.version').text(NProgress.version);
+    NProgress.start();
+    setTimeout(function () {
+        NProgress.done();
+        $('.fade').removeClass('out');
+    }, 1000);
+
+    $("#b-0").click(function () {
+        NProgress.start();
+    });
+    $("#b-40").click(function () {
+        NProgress.set(0.4);
+    });
+    $("#b-inc").click(function () {
+        NProgress.inc();
+    });
+    $("#b-100").click(function () {
+        NProgress.done();
+    });
+
+    var HN = [];
+    HN.factory = function (e) {
+        return function () {
+            HN.push([e].concat(Array.prototype.slice.call(arguments, 0)))
+        };
+    },
+        HN.on = HN.factory("on"),
+        HN.once = HN.factory("once"),
+        HN.off = HN.factory("off"),
+        HN.emit = HN.factory("emit"),
+        HN.load = function () {
+            var e = "hn-button.js";
+            if (document.getElementById(e)) return;
+            var t = document.createElement("script");
+            //t.id=e,t.src="//hn-button.herokuapp.com/hn-button.js";
+            var n = document.getElementsByTagName("script")[0];
+            n.parentNode.insertBefore(t, n)
+        }, HN.load();
+    /**
+     * panda
+     * 页面加载进度条end.
+     */
+})
+
+//表格关闭
+function removeTableMoveEvent(obj) {
+    $(obj).parent().removeClass('Va-table-move');
+    $(obj).remove();
+}
+
+function in_array(val, arr) {
+    for (var i = 0, len = arr.length; i < len; i++) {
+        if (val === arr[i]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// 主题色
+var themeStyle = {
+    index: {
+        themeColors: "#009688",
+        themeTextColors: "#F9F9F9",
+        themeSelectColors: "#606266",
+        headerBackground: "#fff",
+        headerTextColors: "#303133",
+        leftBackground: "#344058",
+        leftTextColors: "#fff",
+        buttonHoverColors: "#009688"
+    },
+    purple: {
+        themeColors: "#d21074",
+        themeTextColors: "#F9F9F9",
+        themeSelectColors: "#606266",
+        headerBackground: "#fff",
+        headerTextColors: "#303133",
+        leftBackground: "#564d67",
+        leftTextColors: "#fff",
+        buttonHoverColors: "#d21074"
+    },
+    blue: {
+        themeColors: "#2790a6",
+        themeTextColors: "#F9F9F9",
+        themeSelectColors: "#606266",
+        headerBackground: "#fff",
+        headerTextColors: "#303133",
+        leftBackground: "#2d6973",
+        leftTextColors: "#fff",
+        buttonHoverColors: "#d21074"
+    }
+}

File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/js/CryptoJS.js


File diff suppressed because it is too large
+ 1 - 0
public/assets/v1/common/js/Sortable.min.js


+ 27421 - 0
public/assets/v1/common/js/aliyun-oss-sdk-6.18.0.min.js

@@ -0,0 +1,27421 @@
+// Aliyun OSS SDK for JavaScript v6.18.0
+// Copyright Aliyun.com, Inc. or its affiliates. All Rights Reserved.
+// License at https://github.com/ali-sdk/ali-oss/blob/master/LICENSE
+(function (global) {
+  !(function (e) {
+    'object' == typeof exports && 'undefined' != typeof module
+      ? (module.exports = e())
+      : 'function' == typeof define && define.amd
+      ? define([], e)
+      : (('undefined' != typeof window
+          ? window
+          : 'undefined' != typeof global
+          ? global
+          : 'undefined' != typeof self
+          ? self
+          : this
+        ).OSS = e());
+  })(function () {
+    return (function n(s, i, o) {
+      function a(t, e) {
+        if (!i[t]) {
+          if (!s[t]) {
+            var r = 'function' == typeof require && require;
+            if (!e && r) return r(t, !0);
+            if (c) return c(t, !0);
+            throw (((e = new Error("Cannot find module '" + t + "'")).code = 'MODULE_NOT_FOUND'), e);
+          }
+          (r = i[t] = { exports: {} }),
+            s[t][0].call(
+              r.exports,
+              function (e) {
+                return a(s[t][1][e] || e);
+              },
+              r,
+              r.exports,
+              n,
+              s,
+              i,
+              o
+            );
+        }
+        return i[t].exports;
+      }
+      for (var c = 'function' == typeof require && require, e = 0; e < o.length; e++) a(o[e]);
+      return a;
+    })(
+      {
+        1: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('./browser/client');
+            (n.Buffer = e('buffer').Buffer),
+              (n.urllib = e('../shims/xhr')),
+              (n.version = e('./browser/version').version),
+              (t.exports = n);
+          },
+          { '../shims/xhr': 449, './browser/client': 3, './browser/version': 6, buffer: 89 }
+        ],
+        2: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              d = n(e('@babel/runtime/regenerator')),
+              i = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              h =
+                (e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.array.slice.js'),
+                e('assert')),
+              s = e('../common/utils/checkBucketName').checkBucketName,
+              n = r;
+            function o(e) {
+              return Array.isArray ? Array.isArray(e) : '[object Array]' === Object.prototype.toString.call(e);
+            }
+            function m(e) {
+              return e ? (o(e) ? e : [e]) : [];
+            }
+            (n.useBucket = function (e) {
+              return s(e), (this.options.bucket = e), this;
+            }),
+              (n.setBucket = function (e) {
+                return s(e), (this.options.bucket = e), this;
+              }),
+              (n.getBucket = function () {
+                return this.options.bucket;
+              }),
+              (n.deleteBucket = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n, s;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (n = this._bucketRequestParams('DELETE', t, '', r)), (e.next = 3), this.request(n);
+                            case 3:
+                              if (200 === (s = e.sent).status || 204 === s.status)
+                                return e.abrupt('return', { res: s.res });
+                              e.next = 6;
+                              break;
+                            case 6:
+                              return (e.next = 8), this.requestError(s);
+                            case 8:
+                              throw e.sent;
+                            case 9:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.putBucketACL = (function () {
+                var n = (0, i.default)(
+                  d.default.mark(function e(t, r, n) {
+                    var s;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((s = this._bucketRequestParams('PUT', t, 'acl', n)).headers = { 'x-oss-acl': r }),
+                                (s.successStatuses = [200]),
+                                (e.next = 5),
+                                this.request(s)
+                              );
+                            case 5:
+                              return (
+                                (s = e.sent),
+                                e.abrupt('return', {
+                                  bucket: (s.headers.location && s.headers.location.substring(1)) || null,
+                                  res: s.res
+                                })
+                              );
+                            case 7:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (n.getBucketACL = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('GET', t, 'acl', r)).successStatuses = [200]),
+                                (n.xmlResponse = !0),
+                                (e.next = 5),
+                                this.request(n)
+                              );
+                            case 5:
+                              return (
+                                (n = e.sent),
+                                e.abrupt('return', {
+                                  acl: n.data.AccessControlList.Grant,
+                                  owner: { id: n.data.Owner.ID, displayName: n.data.Owner.DisplayName },
+                                  res: n.res
+                                })
+                              );
+                            case 7:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.putBucketLogging = (function () {
+                var n = (0, i.default)(
+                  d.default.mark(function e(t, r, n) {
+                    var s, i;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                (s = this._bucketRequestParams('PUT', t, 'logging', n)),
+                                (i =
+                                  '<?xml version="1.0" encoding="UTF-8"?>\n<BucketLoggingStatus>\n<LoggingEnabled>\n<TargetBucket>'.concat(
+                                    t,
+                                    '</TargetBucket>\n'
+                                  )),
+                                r && (i += '<TargetPrefix>'.concat(r, '</TargetPrefix>\n')),
+                                (i += '</LoggingEnabled>\n</BucketLoggingStatus>'),
+                                (s.content = i),
+                                (s.mime = 'xml'),
+                                (s.successStatuses = [200]),
+                                (e.next = 9),
+                                this.request(s)
+                              );
+                            case 9:
+                              return (i = e.sent), e.abrupt('return', { res: i.res });
+                            case 11:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (n.getBucketLogging = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n, s;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('GET', t, 'logging', r)).successStatuses = [200]),
+                                (n.xmlResponse = !0),
+                                (e.next = 5),
+                                this.request(n)
+                              );
+                            case 5:
+                              return (
+                                (n = e.sent),
+                                (s = n.data.LoggingEnabled),
+                                e.abrupt('return', { enable: !!s, prefix: (s && s.TargetPrefix) || null, res: n.res })
+                              );
+                            case 8:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.deleteBucketLogging = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('DELETE', t, 'logging', r)).successStatuses = [
+                                  204, 200
+                                ]),
+                                (e.next = 4),
+                                this.request(n)
+                              );
+                            case 4:
+                              return (n = e.sent), e.abrupt('return', { res: n.res });
+                            case 6:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.putBucketCORS = (function () {
+                var n = (0, i.default)(
+                  d.default.mark(function e(t, r, n) {
+                    var s, i, o, a, c, l, u, p, f;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              for (
+                                h((r = r || []).length, 'rules is required'),
+                                  r.forEach(function (e) {
+                                    h(e.allowedOrigin, 'allowedOrigin is required'),
+                                      h(e.allowedMethod, 'allowedMethod is required');
+                                  }),
+                                  f = this._bucketRequestParams('PUT', t, 'cors', n),
+                                  s = '<?xml version="1.0" encoding="UTF-8"?>\n<CORSConfiguration>',
+                                  i = function (e) {
+                                    s += '<AllowedOrigin>'.concat(e, '</AllowedOrigin>');
+                                  },
+                                  o = function (e) {
+                                    s += '<AllowedMethod>'.concat(e, '</AllowedMethod>');
+                                  },
+                                  a = function (e) {
+                                    s += '<AllowedHeader>'.concat(e, '</AllowedHeader>');
+                                  },
+                                  c = function (e) {
+                                    s += '<ExposeHeader>'.concat(e, '</ExposeHeader>');
+                                  },
+                                  l = 0,
+                                  u = r.length;
+                                l < u;
+                                l++
+                              )
+                                (p = r[l]),
+                                  (s += '<CORSRule>'),
+                                  m(p.allowedOrigin).forEach(i),
+                                  m(p.allowedMethod).forEach(o),
+                                  m(p.allowedHeader).forEach(a),
+                                  m(p.exposeHeader).forEach(c),
+                                  p.maxAgeSeconds &&
+                                    (s += '<MaxAgeSeconds>'.concat(p.maxAgeSeconds, '</MaxAgeSeconds>')),
+                                  (s += '</CORSRule>');
+                              return (
+                                (s += '</CORSConfiguration>'),
+                                (f.content = s),
+                                (f.mime = 'xml'),
+                                (f.successStatuses = [200]),
+                                (e.next = 16),
+                                this.request(f)
+                              );
+                            case 16:
+                              return (f = e.sent), e.abrupt('return', { res: f.res });
+                            case 18:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (n.getBucketCORS = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n, s, i;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('GET', t, 'cors', r)).successStatuses = [200]),
+                                (n.xmlResponse = !0),
+                                (e.next = 5),
+                                this.request(n)
+                              );
+                            case 5:
+                              return (
+                                (n = e.sent),
+                                (s = []),
+                                n.data &&
+                                  n.data.CORSRule &&
+                                  (i = o((i = n.data.CORSRule)) ? i : [i]).forEach(function (t) {
+                                    var r = {};
+                                    Object.keys(t).forEach(function (e) {
+                                      r[e.slice(0, 1).toLowerCase() + e.slice(1, e.length)] = t[e];
+                                    }),
+                                      s.push(r);
+                                  }),
+                                e.abrupt('return', { rules: s, res: n.res })
+                              );
+                            case 9:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.deleteBucketCORS = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('DELETE', t, 'cors', r)).successStatuses = [204]),
+                                (e.next = 4),
+                                this.request(n)
+                              );
+                            case 4:
+                              return (n = e.sent), e.abrupt('return', { res: n.res });
+                            case 6:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.putBucketReferer = (function () {
+                var s = (0, i.default)(
+                  d.default.mark(function e(t, r, n, s) {
+                    var i, o, a;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              if (
+                                ((a = this._bucketRequestParams('PUT', t, 'referer', s)),
+                                (i = '<?xml version="1.0" encoding="UTF-8"?>\n<RefererConfiguration>\n'),
+                                (i += '  <AllowEmptyReferer>'.concat(r ? 'true' : 'false', '</AllowEmptyReferer>\n')),
+                                n && 0 < n.length)
+                              ) {
+                                for (i += '  <RefererList>\n', o = 0; o < n.length; o++)
+                                  i += '    <Referer>'.concat(n[o], '</Referer>\n');
+                                i += '  </RefererList>\n';
+                              } else i += '  <RefererList />\n';
+                              return (
+                                (i += '</RefererConfiguration>'),
+                                (a.content = i),
+                                (a.mime = 'xml'),
+                                (a.successStatuses = [200]),
+                                (e.next = 10),
+                                this.request(a)
+                              );
+                            case 10:
+                              return (a = e.sent), e.abrupt('return', { res: a.res });
+                            case 12:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r, n) {
+                  return s.apply(this, arguments);
+                };
+              })()),
+              (n.getBucketReferer = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    var n, s;
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._bucketRequestParams('GET', t, 'referer', r)).successStatuses = [200]),
+                                (n.xmlResponse = !0),
+                                (e.next = 5),
+                                this.request(n)
+                              );
+                            case 5:
+                              return (
+                                (n = e.sent),
+                                (s = n.data.RefererList.Referer || null) && !o(s) && (s = [s]),
+                                e.abrupt('return', {
+                                  allowEmpty: 'true' === n.data.AllowEmptyReferer,
+                                  referers: s,
+                                  res: n.res
+                                })
+                              );
+                            case 9:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n.deleteBucketReferer = (function () {
+                var r = (0, i.default)(
+                  d.default.mark(function e(t, r) {
+                    return d.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (e.next = 2), this.putBucketReferer(t, !0, null, r);
+                            case 2:
+                              return e.abrupt('return', e.sent);
+                            case 3:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n._bucketRequestParams = function (e, t, r, n) {
+                return { method: e, bucket: t, subres: r, timeout: n && n.timeout, ctx: n && n.ctx };
+              });
+          },
+          {
+            '../common/utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            assert: 81,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        3: [
+          function (E, _, e) {
+            !function (T, k) {
+              !function () {
+                'use strict';
+                var e = E('@babel/runtime/helpers/interopRequireDefault'),
+                  c = e(E('@babel/runtime/regenerator')),
+                  r = e(E('@babel/runtime/helpers/asyncToGenerator')),
+                  e =
+                    (E('core-js/modules/es.function.name.js'),
+                    E('core-js/modules/es.regexp.exec.js'),
+                    E('core-js/modules/es.string.split.js'),
+                    E('core-js/modules/es.object.assign.js'),
+                    E('core-js/modules/es.array.includes.js'),
+                    E('core-js/modules/es.string.replace.js'),
+                    E('core-js/modules/es.array.concat.js'),
+                    E('core-js/modules/es.symbol.js'),
+                    E('core-js/modules/es.symbol.description.js'),
+                    E('core-js/modules/es.array.slice.js'),
+                    E('core-js/modules/es.object.to-string.js'),
+                    E('core-js/modules/es.promise.js'),
+                    E('core-js/modules/es.regexp.to-string.js'),
+                    E('debug')('ali-oss')),
+                  t = E('xml2js'),
+                  n = E('agentkeepalive'),
+                  s = E('merge-descriptors'),
+                  i = E('platform'),
+                  o = E('utility'),
+                  a = E('urllib'),
+                  l = E('./version'),
+                  u = E('bowser'),
+                  p = E('../common/signUtils'),
+                  f = E('../common/client/initOptions'),
+                  d = E('../common/utils/createRequest').createRequest,
+                  h = E('../common/utils/encoder').encoder,
+                  m = E('../common/client/getReqUrl').getReqUrl,
+                  y = E('../common/utils/setSTSToken').setSTSToken,
+                  b = E('../common/utils/retry').retry,
+                  g = E('../common/utils/isFunction').isFunction,
+                  v = new n();
+                function j(e, t) {
+                  var r, n;
+                  if (
+                    ((r = i.name),
+                    (n = i.version),
+                    r &&
+                      r.toLowerCase &&
+                      'ie' === r.toLowerCase() &&
+                      n.split('.')[0] < 10 &&
+                      console.warn('ali-oss does not support the current browser'),
+                    !(this instanceof j))
+                  )
+                    return new j(e, t);
+                  e && e.inited ? (this.options = e) : (this.options = j.initOptions(e)),
+                    (this.options.cancelFlag = !1),
+                    this.options.urllib
+                      ? (this.urllib = this.options.urllib)
+                      : ((this.urllib = a), (this.agent = this.options.agent || v)),
+                    (this.ctx = t),
+                    (this.userAgent = this._getUserAgent()),
+                    (this.stsTokenFreshTime = new Date()),
+                    (this.options.amendTimeSkewed = 0);
+                }
+                (_.exports = j).initOptions = function (e) {
+                  e.stsToken ||
+                    console.warn(
+                      'Please use STS Token for safety, see more details at https://help.aliyun.com/document_detail/32077.html'
+                    );
+                  e = Object.assign({ secure: location && 'https:' === location.protocol, useFetch: !1 }, e);
+                  return f(e);
+                };
+                n = j.prototype;
+                function w(e) {
+                  return x.apply(this, arguments);
+                }
+                function x() {
+                  return (x = (0, r.default)(
+                    c.default.mark(function e(t) {
+                      var r, n, s, i, o, a;
+                      return c.default.wrap(
+                        function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                if (this.options.stsToken && g(this.options.refreshSTSToken))
+                                  return (e.next = 3), y.call(this);
+                                e.next = 3;
+                                break;
+                              case 3:
+                                return (
+                                  (r = d.call(this, t)),
+                                  this.options.useFetch || (r.params.mode = 'disable-fetch'),
+                                  (i = !!t.stream),
+                                  (e.prev = 6),
+                                  (e.next = 9),
+                                  this.urllib.request(r.url, r.params)
+                                );
+                              case 9:
+                                (n = e.sent),
+                                  this.debug(
+                                    'response %s %s, got %s, headers: %j',
+                                    t.method,
+                                    r.url,
+                                    n.status,
+                                    n.headers,
+                                    'info'
+                                  ),
+                                  (e.next = 16);
+                                break;
+                              case 13:
+                                (e.prev = 13), (e.t0 = e.catch(6)), (s = e.t0);
+                              case 16:
+                                if (n && t.successStatuses && -1 === t.successStatuses.indexOf(n.status))
+                                  return (e.next = 19), this.requestError(n);
+                                e.next = 28;
+                                break;
+                              case 19:
+                                if ('RequestTimeTooSkewed' !== (o = e.sent).code || i) {
+                                  e.next = 25;
+                                  break;
+                                }
+                                return (
+                                  (this.options.amendTimeSkewed = +new Date(o.serverTime) - new Date()),
+                                  (e.next = 24),
+                                  this.request(t)
+                                );
+                              case 24:
+                                return e.abrupt('return', e.sent);
+                              case 25:
+                                (o.params = t), (e.next = 32);
+                                break;
+                              case 28:
+                                if (s) return (e.next = 31), this.requestError(s);
+                                e.next = 32;
+                                break;
+                              case 31:
+                                o = e.sent;
+                              case 32:
+                                if (o) throw o;
+                                e.next = 34;
+                                break;
+                              case 34:
+                                if (t.xmlResponse) return (e.next = 37), this.parseXML(n.data);
+                                e.next = 39;
+                                break;
+                              case 37:
+                                (a = e.sent), (n.data = a);
+                              case 39:
+                                return e.abrupt('return', n);
+                              case 40:
+                              case 'end':
+                                return e.stop();
+                            }
+                        },
+                        e,
+                        this,
+                        [[6, 13]]
+                      );
+                    })
+                  )).apply(this, arguments);
+                }
+                (n.debug = e),
+                  s(n, E('./object')),
+                  s(n, E('./bucket')),
+                  s(n, E('../common/bucket/getBucketWebsite')),
+                  s(n, E('../common/bucket/putBucketWebsite')),
+                  s(n, E('../common/bucket/deleteBucketWebsite')),
+                  s(n, E('../common/bucket/getBucketLifecycle')),
+                  s(n, E('../common/bucket/putBucketLifecycle')),
+                  s(n, E('../common/bucket/deleteBucketLifecycle')),
+                  s(n, E('../common/bucket/putBucketVersioning')),
+                  s(n, E('../common/bucket/getBucketVersioning')),
+                  s(n, E('../common/bucket/getBucketInventory')),
+                  s(n, E('../common/bucket/deleteBucketInventory')),
+                  s(n, E('../common/bucket/listBucketInventory')),
+                  s(n, E('../common/bucket/putBucketInventory')),
+                  s(n, E('../common/bucket/abortBucketWorm')),
+                  s(n, E('../common/bucket/completeBucketWorm')),
+                  s(n, E('../common/bucket/extendBucketWorm')),
+                  s(n, E('../common/bucket/getBucketWorm')),
+                  s(n, E('../common/bucket/initiateBucketWorm')),
+                  s(n, E('./managed-upload')),
+                  s(n, E('../common/multipart-copy')),
+                  s(n, E('../common/multipart')),
+                  s(n, E('../common/parallel')),
+                  (n.signature = function (e) {
+                    return (
+                      this.debug('authorization stringToSign: %s', e, 'info'),
+                      p.computeSignature(this.options.accessKeySecret, e, this.options.headerEncoding)
+                    );
+                  }),
+                  (n._getReqUrl = m),
+                  (n.authorization = function (e, t, r, n) {
+                    e = p.buildCanonicalString(e.toUpperCase(), t, { headers: n, parameters: r });
+                    return p.authorization(
+                      this.options.accessKeyId,
+                      this.options.accessKeySecret,
+                      e,
+                      this.options.headerEncoding
+                    );
+                  }),
+                  (n.request = (function () {
+                    var t = (0, r.default)(
+                      c.default.mark(function e(n) {
+                        var s = this;
+                        return c.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  if (this.options.retryMax)
+                                    return (
+                                      (e.next = 3),
+                                      b(w.bind(this), this.options.retryMax, {
+                                        errorHandler: function (e) {
+                                          return !!(function (e) {
+                                            if (n.stream) return !1;
+                                            var t = [-1, -2].includes(e.status),
+                                              r =
+                                                s.options.requestErrorRetryHandle ||
+                                                function () {
+                                                  return !0;
+                                                };
+                                            return t && r(e);
+                                          })(e);
+                                        }
+                                      })(n)
+                                    );
+                                  e.next = 6;
+                                  break;
+                                case 3:
+                                  return e.abrupt('return', e.sent);
+                                case 6:
+                                  return e.abrupt('return', w.call(this, n));
+                                case 7:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e) {
+                      return t.apply(this, arguments);
+                    };
+                  })()),
+                  (n._getResource = function (e) {
+                    var t = '/';
+                    return (
+                      e.bucket && (t += ''.concat(e.bucket, '/')),
+                      e.object && (t += h(e.object, this.options.headerEncoding)),
+                      t
+                    );
+                  }),
+                  (n._escape = function (e) {
+                    return o.encodeURIComponent(e).replace(/%2F/g, '/');
+                  }),
+                  (n._getUserAgent = function () {
+                    var e = k && k.browser ? 'js' : 'nodejs',
+                      e = 'aliyun-sdk-'.concat(e, '/').concat(l.version),
+                      t = i.description;
+                    return (
+                      !t &&
+                        k &&
+                        (t = 'Node.js '.concat(k.version.slice(1), ' on ').concat(k.platform, ' ').concat(k.arch)),
+                      this._checkUserAgent(''.concat(e, ' ').concat(t))
+                    );
+                  }),
+                  (n._checkUserAgent = function (e) {
+                    return e.replace(/\u03b1/, 'alpha').replace(/\u03b2/, 'beta');
+                  }),
+                  (n.checkBrowserAndVersion = function (e, t) {
+                    return u.name === e && u.version.split('.')[0] === t;
+                  }),
+                  (n.parseXML = function (e) {
+                    return new Promise(function (r, n) {
+                      T.isBuffer(e) && (e = e.toString()),
+                        t.parseString(e, { explicitRoot: !1, explicitArray: !1 }, function (e, t) {
+                          e ? n(e) : r(t);
+                        });
+                    });
+                  }),
+                  (n.requestError = (function () {
+                    var t = (0, r.default)(
+                      c.default.mark(function e(t) {
+                        var r, n, s, i;
+                        return c.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  if (((r = null), t.data && t.data.length)) {
+                                    e.next = 5;
+                                    break;
+                                  }
+                                  -1 === t.status || -2 === t.status
+                                    ? (((r = new Error(t.message)).name = t.name),
+                                      (r.status = t.status),
+                                      (r.code = t.name))
+                                    : (404 === t.status
+                                        ? (((r = new Error('Object not exists')).name = 'NoSuchKeyError'),
+                                          (r.status = 404),
+                                          (r.code = 'NoSuchKey'))
+                                        : 412 === t.status
+                                        ? (((r = new Error('Pre condition failed')).name = 'PreconditionFailedError'),
+                                          (r.status = 412),
+                                          (r.code = 'PreconditionFailed'))
+                                        : (((r = new Error('Unknow error, status: '.concat(t.status))).name =
+                                            'UnknownError'),
+                                          (r.status = t.status)),
+                                      (r.requestId = t.headers['x-oss-request-id']),
+                                      (r.host = '')),
+                                    (e.next = 32);
+                                  break;
+                                case 5:
+                                  return (
+                                    (n = String(t.data)),
+                                    this.debug('request response error data: %s', n, 'error'),
+                                    (e.prev = 7),
+                                    (e.next = 10),
+                                    this.parseXML(n)
+                                  );
+                                case 10:
+                                  if (((e.t0 = e.sent), e.t0)) {
+                                    e.next = 13;
+                                    break;
+                                  }
+                                  e.t0 = {};
+                                case 13:
+                                  (s = e.t0), (e.next = 23);
+                                  break;
+                                case 16:
+                                  return (
+                                    (e.prev = 16),
+                                    (e.t1 = e.catch(7)),
+                                    this.debug(n, 'error'),
+                                    (e.t1.message += '\nraw xml: '.concat(n)),
+                                    (e.t1.status = t.status),
+                                    (e.t1.requestId = t.headers['x-oss-request-id']),
+                                    e.abrupt('return', e.t1)
+                                  );
+                                case 23:
+                                  (i = s.Message || 'unknow request error, status: '.concat(t.status)),
+                                    s.Condition && (i += ' (condition: '.concat(s.Condition, ')')),
+                                    ((r = new Error(i)).name = s.Code ? ''.concat(s.Code, 'Error') : 'UnknownError'),
+                                    (r.status = t.status),
+                                    (r.code = s.Code),
+                                    (r.requestId = s.RequestId),
+                                    (r.hostId = s.HostId),
+                                    (r.serverTime = s.ServerTime);
+                                case 32:
+                                  return this.debug('generate error %j', r, 'error'), e.abrupt('return', r);
+                                case 34:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this,
+                          [[7, 16]]
+                        );
+                      })
+                    );
+                    return function (e) {
+                      return t.apply(this, arguments);
+                    };
+                  })());
+              }.call(this);
+            }.call(this, { isBuffer: E('../../node_modules/is-buffer/index.js') }, E('_process'));
+          },
+          {
+            '../../node_modules/is-buffer/index.js': 354,
+            '../common/bucket/abortBucketWorm': 7,
+            '../common/bucket/completeBucketWorm': 8,
+            '../common/bucket/deleteBucketInventory': 9,
+            '../common/bucket/deleteBucketLifecycle': 10,
+            '../common/bucket/deleteBucketWebsite': 11,
+            '../common/bucket/extendBucketWorm': 12,
+            '../common/bucket/getBucketInventory': 13,
+            '../common/bucket/getBucketLifecycle': 14,
+            '../common/bucket/getBucketVersioning': 15,
+            '../common/bucket/getBucketWebsite': 16,
+            '../common/bucket/getBucketWorm': 17,
+            '../common/bucket/initiateBucketWorm': 18,
+            '../common/bucket/listBucketInventory': 19,
+            '../common/bucket/putBucketInventory': 20,
+            '../common/bucket/putBucketLifecycle': 21,
+            '../common/bucket/putBucketVersioning': 22,
+            '../common/bucket/putBucketWebsite': 23,
+            '../common/client/getReqUrl': 25,
+            '../common/client/initOptions': 26,
+            '../common/multipart': 30,
+            '../common/multipart-copy': 29,
+            '../common/parallel': 49,
+            '../common/signUtils': 50,
+            '../common/utils/createRequest': 55,
+            '../common/utils/encoder': 58,
+            '../common/utils/isFunction': 66,
+            '../common/utils/retry': 72,
+            '../common/utils/setSTSToken': 74,
+            './bucket': 2,
+            './managed-upload': 4,
+            './object': 5,
+            './version': 6,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            _process: 441,
+            agentkeepalive: 80,
+            bowser: 86,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/es.string.split.js': 306,
+            'core-js/modules/es.symbol.description.js': 309,
+            'core-js/modules/es.symbol.js': 312,
+            debug: 439,
+            'merge-descriptors': 357,
+            platform: 364,
+            urllib: 449,
+            utility: 448,
+            xml2js: 400
+          }
+        ],
+        4: [
+          function (s, e, i) {
+            !function (o) {
+              !function () {
+                'use strict';
+                var e = s('@babel/runtime/helpers/interopRequireDefault'),
+                  b = e(s('@babel/runtime/regenerator')),
+                  g =
+                    (s('core-js/modules/es.function.name.js'),
+                    s('core-js/modules/es.object.to-string.js'),
+                    s('core-js/modules/es.promise.js'),
+                    s('core-js/modules/es.array.from.js'),
+                    s('core-js/modules/es.string.iterator.js'),
+                    s('core-js/modules/es.array.map.js'),
+                    s('core-js/modules/es.array.filter.js'),
+                    s('core-js/modules/es.array.find.js'),
+                    s('core-js/modules/es.array.concat.js'),
+                    s('core-js/modules/es.regexp.to-string.js'),
+                    s('core-js/modules/es.array.slice.js'),
+                    s('core-js/modules/es.array.iterator.js'),
+                    s('core-js/modules/es.array-buffer.slice.js'),
+                    s('core-js/modules/es.typed-array.uint8-array.js'),
+                    s('core-js/modules/es.typed-array.copy-within.js'),
+                    s('core-js/modules/es.typed-array.every.js'),
+                    s('core-js/modules/es.typed-array.fill.js'),
+                    s('core-js/modules/es.typed-array.filter.js'),
+                    s('core-js/modules/es.typed-array.find.js'),
+                    s('core-js/modules/es.typed-array.find-index.js'),
+                    s('core-js/modules/es.typed-array.for-each.js'),
+                    s('core-js/modules/es.typed-array.includes.js'),
+                    s('core-js/modules/es.typed-array.index-of.js'),
+                    s('core-js/modules/es.typed-array.iterator.js'),
+                    s('core-js/modules/es.typed-array.join.js'),
+                    s('core-js/modules/es.typed-array.last-index-of.js'),
+                    s('core-js/modules/es.typed-array.map.js'),
+                    s('core-js/modules/es.typed-array.reduce.js'),
+                    s('core-js/modules/es.typed-array.reduce-right.js'),
+                    s('core-js/modules/es.typed-array.reverse.js'),
+                    s('core-js/modules/es.typed-array.set.js'),
+                    s('core-js/modules/es.typed-array.slice.js'),
+                    s('core-js/modules/es.typed-array.some.js'),
+                    s('core-js/modules/es.typed-array.sort.js'),
+                    s('core-js/modules/es.typed-array.subarray.js'),
+                    s('core-js/modules/es.typed-array.to-locale-string.js'),
+                    s('core-js/modules/es.typed-array.to-string.js'),
+                    e(s('@babel/runtime/helpers/asyncToGenerator'))),
+                  e = s('util'),
+                  p = s('path'),
+                  f = s('mime'),
+                  v = s('copy-to'),
+                  d = s('../common/utils/isBlob').isBlob,
+                  h = s('../common/utils/isFile').isFile,
+                  m = s('../common/utils/isBuffer').isBuffer,
+                  t = i;
+                (t.multipartUpload = (function () {
+                  var r = (0, g.default)(
+                    b.default.mark(function e(t, r) {
+                      var n,
+                        s,
+                        i,
+                        o,
+                        a,
+                        c,
+                        l,
+                        u = arguments;
+                      return b.default.wrap(
+                        function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                if (
+                                  ((n = 2 < u.length && void 0 !== u[2] ? u[2] : {}),
+                                  this.resetCancelFlag(),
+                                  (n.disabledMD5 = void 0 === n.disabledMD5 || !!n.disabledMD5),
+                                  n.checkpoint && n.checkpoint.uploadId)
+                                )
+                                  return (
+                                    r && h(r) && (n.checkpoint.file = r),
+                                    (e.next = 7),
+                                    this._resumeMultipart(n.checkpoint, n)
+                                  );
+                                e.next = 8;
+                                break;
+                              case 7:
+                                return e.abrupt('return', e.sent);
+                              case 8:
+                                return (
+                                  (s = 102400),
+                                  n.mime ||
+                                    (h(r)
+                                      ? (n.mime = f.getType(p.extname(r.name)))
+                                      : d(r)
+                                      ? (n.mime = r.type)
+                                      : m(r)
+                                      ? (n.mime = '')
+                                      : (n.mime = f.getType(p.extname(r)))),
+                                  (n.headers = n.headers || {}),
+                                  this._convertMetaToHeaders(n.meta, n.headers),
+                                  (e.next = 14),
+                                  this._getFileSize(r)
+                                );
+                              case 14:
+                                if ((i = e.sent) < s) return (n.contentLength = i), (e.next = 19), this.put(t, r, n);
+                                e.next = 26;
+                                break;
+                              case 19:
+                                if (((o = e.sent), n && n.progress)) return (e.next = 23), n.progress(1);
+                                e.next = 23;
+                                break;
+                              case 23:
+                                return (
+                                  (a = { res: o.res, bucket: this.options.bucket, name: t, etag: o.res.headers.etag }),
+                                  ((n.headers && n.headers['x-oss-callback']) || n.callback) && (a.data = o.data),
+                                  e.abrupt('return', a)
+                                );
+                              case 26:
+                                if (n.partSize && parseInt(n.partSize, 10) !== n.partSize)
+                                  throw new Error('partSize must be int number');
+                                e.next = 28;
+                                break;
+                              case 28:
+                                if (n.partSize && n.partSize < s)
+                                  throw new Error('partSize must not be smaller than '.concat(s));
+                                e.next = 30;
+                                break;
+                              case 30:
+                                return (e.next = 32), this.initMultipartUpload(t, n);
+                              case 32:
+                                if (
+                                  ((a = e.sent),
+                                  (c = a.uploadId),
+                                  (l = this._getPartSize(i, n.partSize)),
+                                  (l = { file: r, name: t, fileSize: i, partSize: l, uploadId: c, doneParts: [] }),
+                                  n && n.progress)
+                                )
+                                  return (e.next = 39), n.progress(0, l, a.res);
+                                e.next = 39;
+                                break;
+                              case 39:
+                                return (e.next = 41), this._resumeMultipart(l, n);
+                              case 41:
+                                return e.abrupt('return', e.sent);
+                              case 42:
+                              case 'end':
+                                return e.stop();
+                            }
+                        },
+                        e,
+                        this
+                      );
+                    })
+                  );
+                  return function (e, t) {
+                    return r.apply(this, arguments);
+                  };
+                })()),
+                  (t._resumeMultipart = (function () {
+                    var r = (0, g.default)(
+                      b.default.mark(function e(c, l) {
+                        var n, u, p, f, d, s, h, m, y, i, t, r, o, a;
+                        return b.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  if ((n = this).isCancel()) throw this._makeCancelEvent();
+                                  e.next = 3;
+                                  break;
+                                case 3:
+                                  return (
+                                    (u = c.file),
+                                    (r = c.fileSize),
+                                    (a = c.partSize),
+                                    (p = c.uploadId),
+                                    (f = c.doneParts),
+                                    (d = c.name),
+                                    (s = []),
+                                    0 < f.length && v(f).to(s),
+                                    (h = this._divideParts(r, a)),
+                                    (m = h.length),
+                                    (y = !1),
+                                    (i = function (o, a) {
+                                      return new Promise(
+                                        (function () {
+                                          var r = (0, g.default)(
+                                            b.default.mark(function e(t, r) {
+                                              var n, s, i;
+                                              return b.default.wrap(
+                                                function (e) {
+                                                  for (;;)
+                                                    switch ((e.prev = e.next)) {
+                                                      case 0:
+                                                        if (((e.prev = 0), o.isCancel())) {
+                                                          e.next = 29;
+                                                          break;
+                                                        }
+                                                        return (
+                                                          (n = h[a - 1]),
+                                                          (e.next = 5),
+                                                          o._createBuffer(u, n.start, n.end)
+                                                        );
+                                                      case 5:
+                                                        return (
+                                                          (i = e.sent),
+                                                          (i = { content: i, size: n.end - n.start }),
+                                                          (e.prev = 7),
+                                                          (e.next = 10),
+                                                          o._uploadPart(d, p, a, i, l)
+                                                        );
+                                                      case 10:
+                                                        (s = e.sent), (e.next = 18);
+                                                        break;
+                                                      case 13:
+                                                        if (((e.prev = 13), (e.t0 = e.catch(7)), 404 === e.t0.status))
+                                                          throw o._makeAbortEvent();
+                                                        e.next = 17;
+                                                        break;
+                                                      case 17:
+                                                        throw e.t0;
+                                                      case 18:
+                                                        if (o.isCancel() || y) {
+                                                          e.next = 26;
+                                                          break;
+                                                        }
+                                                        if (
+                                                          (c.doneParts.push({ number: a, etag: s.res.headers.etag }),
+                                                          l.progress)
+                                                        )
+                                                          return (
+                                                            (e.next = 23), l.progress(f.length / (m + 1), c, s.res)
+                                                          );
+                                                        e.next = 23;
+                                                        break;
+                                                      case 23:
+                                                        t({ number: a, etag: s.res.headers.etag }), (e.next = 27);
+                                                        break;
+                                                      case 26:
+                                                        t();
+                                                      case 27:
+                                                        e.next = 30;
+                                                        break;
+                                                      case 29:
+                                                        t();
+                                                      case 30:
+                                                        e.next = 41;
+                                                        break;
+                                                      case 32:
+                                                        (e.prev = 32),
+                                                          (e.t1 = e.catch(0)),
+                                                          ((i = new Error()).name = e.t1.name),
+                                                          (i.message = e.t1.message),
+                                                          (i.stack = e.t1.stack),
+                                                          (i.partNum = a),
+                                                          v(e.t1).to(i),
+                                                          r(i);
+                                                      case 41:
+                                                      case 'end':
+                                                        return e.stop();
+                                                    }
+                                                },
+                                                e,
+                                                null,
+                                                [
+                                                  [0, 32],
+                                                  [7, 13]
+                                                ]
+                                              );
+                                            })
+                                          );
+                                          return function (e, t) {
+                                            return r.apply(this, arguments);
+                                          };
+                                        })()
+                                      );
+                                    }),
+                                    (r = Array.from(new Array(m), function (e, t) {
+                                      return t + 1;
+                                    })),
+                                    (t = s.map(function (e) {
+                                      return e.number;
+                                    })),
+                                    (a = r.filter(function (e) {
+                                      return t.indexOf(e) < 0;
+                                    })),
+                                    (r = l.parallel || 5),
+                                    (e.next = 17),
+                                    this._parallel(a, r, function (e) {
+                                      return new Promise(function (t, r) {
+                                        i(n, e)
+                                          .then(function (e) {
+                                            e && s.push(e), t();
+                                          })
+                                          .catch(function (e) {
+                                            r(e);
+                                          });
+                                      });
+                                    })
+                                  );
+                                case 17:
+                                  if (
+                                    ((o = e.sent),
+                                    (y = !0),
+                                    (a = o.find(function (e) {
+                                      return 'abort' === e.name;
+                                    })))
+                                  )
+                                    throw a;
+                                  e.next = 22;
+                                  break;
+                                case 22:
+                                  if (this.isCancel()) throw ((i = null), this._makeCancelEvent());
+                                  e.next = 25;
+                                  break;
+                                case 25:
+                                  if (o && 0 < o.length)
+                                    throw (
+                                      ((o[0].message = 'Failed to upload some parts with error: '
+                                        .concat(o[0].toString(), ' part_num: ')
+                                        .concat(o[0].partNum)),
+                                      o[0])
+                                    );
+                                  e.next = 28;
+                                  break;
+                                case 28:
+                                  return (e.next = 30), this.completeMultipartUpload(d, p, s, l);
+                                case 30:
+                                  return e.abrupt('return', e.sent);
+                                case 31:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t) {
+                      return r.apply(this, arguments);
+                    };
+                  })()),
+                  (t._getFileSize = (function () {
+                    var t = (0, g.default)(
+                      b.default.mark(function e(t) {
+                        return b.default.wrap(function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                if (m(t)) return e.abrupt('return', t.length);
+                                e.next = 4;
+                                break;
+                              case 4:
+                                if (d(t) || h(t)) return e.abrupt('return', t.size);
+                                e.next = 6;
+                                break;
+                              case 6:
+                                throw new Error('_getFileSize requires Buffer/File/Blob.');
+                              case 7:
+                              case 'end':
+                                return e.stop();
+                            }
+                        }, e);
+                      })
+                    );
+                    return function (e) {
+                      return t.apply(this, arguments);
+                    };
+                  })());
+                var r = s('stream').Readable;
+                function n(e, t) {
+                  if (!(this instanceof n)) return new n(e, t);
+                  r.call(this, t),
+                    (this.file = e),
+                    (this.reader = new FileReader()),
+                    (this.start = 0),
+                    (this.finish = !1),
+                    (this.fileBuffer = null);
+                }
+                e.inherits(n, r),
+                  (n.prototype.readFileAndPush = function (e) {
+                    if (this.fileBuffer)
+                      for (var t = !0; t && this.fileBuffer && this.start < this.fileBuffer.length; ) {
+                        var r = this.start,
+                          n = (n = r + e) > this.fileBuffer.length ? this.fileBuffer.length : n;
+                        (this.start = n), (t = this.push(this.fileBuffer.slice(r, n)));
+                      }
+                  }),
+                  (n.prototype._read = function (t) {
+                    if (
+                      (this.file && this.start >= this.file.size) ||
+                      (this.fileBuffer && this.start >= this.fileBuffer.length) ||
+                      this.finish ||
+                      (0 === this.start && !this.file)
+                    )
+                      return this.finish || ((this.fileBuffer = null), (this.finish = !0)), void this.push(null);
+                    t = t || 16384;
+                    var r = this;
+                    (this.reader.onload = function (e) {
+                      (r.fileBuffer = o.from(new Uint8Array(e.target.result))), (r.file = null), r.readFileAndPush(t);
+                    }),
+                      0 === this.start ? this.reader.readAsArrayBuffer(this.file) : this.readFileAndPush(t);
+                  }),
+                  (t._createBuffer = (function () {
+                    var n = (0, g.default)(
+                      b.default.mark(function e(t, r, s) {
+                        var i;
+                        return b.default.wrap(function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                if (!d(t) && !h(t)) {
+                                  e.next = 8;
+                                  break;
+                                }
+                                (i = t.slice(r, s)), (e.next = 4);
+                                var n = i;
+                                return n.arrayBuffer
+                                  ? n.arrayBuffer()
+                                  : new Promise(function (t, r) {
+                                      var e = new FileReader();
+                                      (e.onload = function (e) {
+                                        t(e.target.result);
+                                      }),
+                                        (e.onerror = function (e) {
+                                          r(e);
+                                        }),
+                                        e.readAsArrayBuffer(n);
+                                    });
+                              case 4:
+                                return (i = e.sent), e.abrupt('return', o.from(i));
+                              case 8:
+                                if (m(t)) return e.abrupt('return', t.subarray(r, s));
+                                e.next = 12;
+                                break;
+                              case 12:
+                                throw new Error('_createBuffer requires File/Blob/Buffer.');
+                              case 13:
+                              case 'end':
+                                return e.stop();
+                            }
+                        }, e);
+                      })
+                    );
+                    return function (e, t, r) {
+                      return n.apply(this, arguments);
+                    };
+                  })()),
+                  (t._getPartSize = function (e, t) {
+                    t = t || 1048576;
+                    e = Math.ceil(e / 1e4);
+                    return (
+                      t < e &&
+                        ((t = e),
+                        console.warn(
+                          'partSize has been set to '.concat(
+                            t,
+                            ', because the partSize you provided causes partNumber to be greater than 10,000'
+                          )
+                        )),
+                      t
+                    );
+                  }),
+                  (t._divideParts = function (e, t) {
+                    for (var r = Math.ceil(e / t), n = [], s = 0; s < r; s++) {
+                      var i = t * s,
+                        o = Math.min(i + t, e);
+                      n.push({ start: i, end: o });
+                    }
+                    return n;
+                  });
+              }.call(this);
+            }.call(this, s('buffer').Buffer);
+          },
+          {
+            '../common/utils/isBlob': 63,
+            '../common/utils/isBuffer': 64,
+            '../common/utils/isFile': 65,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            buffer: 89,
+            'copy-to': 91,
+            'core-js/modules/es.array-buffer.slice.js': 268,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.filter.js': 271,
+            'core-js/modules/es.array.find.js': 272,
+            'core-js/modules/es.array.from.js': 273,
+            'core-js/modules/es.array.iterator.js': 275,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.iterator.js': 302,
+            'core-js/modules/es.typed-array.copy-within.js': 314,
+            'core-js/modules/es.typed-array.every.js': 315,
+            'core-js/modules/es.typed-array.fill.js': 316,
+            'core-js/modules/es.typed-array.filter.js': 317,
+            'core-js/modules/es.typed-array.find-index.js': 318,
+            'core-js/modules/es.typed-array.find.js': 319,
+            'core-js/modules/es.typed-array.for-each.js': 320,
+            'core-js/modules/es.typed-array.includes.js': 321,
+            'core-js/modules/es.typed-array.index-of.js': 322,
+            'core-js/modules/es.typed-array.iterator.js': 323,
+            'core-js/modules/es.typed-array.join.js': 324,
+            'core-js/modules/es.typed-array.last-index-of.js': 325,
+            'core-js/modules/es.typed-array.map.js': 326,
+            'core-js/modules/es.typed-array.reduce-right.js': 327,
+            'core-js/modules/es.typed-array.reduce.js': 328,
+            'core-js/modules/es.typed-array.reverse.js': 329,
+            'core-js/modules/es.typed-array.set.js': 330,
+            'core-js/modules/es.typed-array.slice.js': 331,
+            'core-js/modules/es.typed-array.some.js': 332,
+            'core-js/modules/es.typed-array.sort.js': 333,
+            'core-js/modules/es.typed-array.subarray.js': 334,
+            'core-js/modules/es.typed-array.to-locale-string.js': 335,
+            'core-js/modules/es.typed-array.to-string.js': 336,
+            'core-js/modules/es.typed-array.uint8-array.js': 337,
+            mime: 359,
+            path: 363,
+            stream: 387,
+            util: 394
+          }
+        ],
+        5: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              c =
+                (e('core-js/modules/es.function.name.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/es.regexp.to-string.js'),
+                e('core-js/modules/es.array.map.js'),
+                e('core-js/modules/es.number.constructor.js'),
+                e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.string.replace.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.promise.js'),
+                n(e('@babel/runtime/regenerator'))),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              i = e('fs'),
+              o = e('copy-to'),
+              l = e('path'),
+              u = e('mime'),
+              p = e('../common/callback'),
+              n = e('merge-descriptors'),
+              f = e('../common/utils/isBlob').isBlob,
+              d = e('../common/utils/isFile').isFile,
+              h = e('../common/utils/isBuffer').isBuffer,
+              a = e('../common/utils/obj2xml').obj2xml;
+            (r.append = (function () {
+              var n = (0, s.default)(
+                c.default.mark(function e(t, r, n) {
+                  var s;
+                  return c.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              void 0 === (n = n || {}).position && (n.position = '0'),
+                              (n.subres = { append: '', position: n.position }),
+                              (n.method = 'POST'),
+                              (e.next = 6),
+                              this.put(t, r, n)
+                            );
+                          case 6:
+                            return (
+                              ((s = e.sent).nextAppendPosition = s.res.headers['x-oss-next-append-position']),
+                              e.abrupt('return', s)
+                            );
+                          case 9:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r) {
+                return n.apply(this, arguments);
+              };
+            })()),
+              (r.put = (function () {
+                var n = (0, s.default)(
+                  c.default.mark(function e(t, r, n) {
+                    var s, i, o, a;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              if (
+                                (((n = n || {}).disabledMD5 = void 0 === n.disabledMD5 || !!n.disabledMD5),
+                                (n.headers = n.headers || {}),
+                                (t = this._objectName(t)),
+                                !h(r))
+                              ) {
+                                e.next = 8;
+                                break;
+                              }
+                              (s = r), (e.next = 19);
+                              break;
+                            case 8:
+                              if (f(r) || d(r))
+                                return (
+                                  n.mime || (d(r) ? (n.mime = u.getType(l.extname(r.name))) : (n.mime = r.type)),
+                                  (e.next = 12),
+                                  this._createBuffer(r, 0, r.size)
+                                );
+                              e.next = 18;
+                              break;
+                            case 12:
+                              return (s = e.sent), (e.next = 15), this._getFileSize(r);
+                            case 15:
+                              (n.contentLength = e.sent), (e.next = 19);
+                              break;
+                            case 18:
+                              throw new TypeError('Must provide Buffer/Blob/File for put.');
+                            case 19:
+                              return (
+                                this._convertMetaToHeaders(n.meta, n.headers),
+                                (i = n.method || 'PUT'),
+                                (i = this._objectRequestParams(i, t, n)),
+                                p.encodeCallback(i, n),
+                                (i.mime = n.mime),
+                                (i.disabledMD5 = n.disabledMD5),
+                                (i.content = s),
+                                (i.successStatuses = [200]),
+                                (e.next = 29),
+                                this.request(i)
+                              );
+                            case 29:
+                              return (
+                                (o = e.sent),
+                                (a = { name: t, url: this._objectUrl(t), res: o.res }),
+                                i.headers && i.headers['x-oss-callback'] && (a.data = JSON.parse(o.data.toString())),
+                                e.abrupt('return', a)
+                              );
+                            case 33:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (r.putStream = (function () {
+                var n = (0, s.default)(
+                  c.default.mark(function e(t, r, n) {
+                    var s, i, o;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = n || {}).headers = n.headers || {}),
+                                (t = this._objectName(t)),
+                                n.contentLength
+                                  ? (n.headers['Content-Length'] = n.contentLength)
+                                  : (n.headers['Transfer-Encoding'] = 'chunked'),
+                                this._convertMetaToHeaders(n.meta, n.headers),
+                                (s = n.method || 'PUT'),
+                                (s = this._objectRequestParams(s, t, n)),
+                                p.encodeCallback(s, n),
+                                (s.mime = n.mime),
+                                (s.stream = r),
+                                (s.successStatuses = [200]),
+                                (e.next = 13),
+                                this.request(s)
+                              );
+                            case 13:
+                              return (
+                                (i = e.sent),
+                                (o = { name: t, url: this._objectUrl(t), res: i.res }),
+                                s.headers && s.headers['x-oss-callback'] && (o.data = JSON.parse(i.data.toString())),
+                                e.abrupt('return', o)
+                              );
+                            case 17:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              n(r, e('../common/object/copyObject')),
+              n(r, e('../common/object/getObjectTagging')),
+              n(r, e('../common/object/putObjectTagging')),
+              n(r, e('../common/object/deleteObjectTagging')),
+              n(r, e('../common/image')),
+              n(r, e('../common/object/getBucketVersions')),
+              n(r, e('../common/object/getACL')),
+              n(r, e('../common/object/putACL')),
+              n(r, e('../common/object/head')),
+              n(r, e('../common/object/delete')),
+              n(r, e('../common/object/get')),
+              n(r, e('../common/object/putSymlink')),
+              n(r, e('../common/object/getSymlink')),
+              n(r, e('../common/object/deleteMulti')),
+              n(r, e('../common/object/getObjectMeta')),
+              n(r, e('../common/object/getObjectUrl')),
+              n(r, e('../common/object/generateObjectUrl')),
+              n(r, e('../common/object/signatureUrl')),
+              n(r, e('../common/object/asyncSignatureUrl')),
+              (r.putMeta = (function () {
+                var n = (0, s.default)(
+                  c.default.mark(function e(t, r, n) {
+                    var s;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                (e.next = 2),
+                                this.copy(t, t, { meta: r || {}, timeout: n && n.timeout, ctx: n && n.ctx })
+                              );
+                            case 2:
+                              return (s = e.sent), e.abrupt('return', s);
+                            case 4:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (r.list = (function () {
+                var r = (0, s.default)(
+                  c.default.mark(function e(t, r) {
+                    var n, s, i, o;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = this._objectRequestParams('GET', '', r)).query = t),
+                                (n.xmlResponse = !0),
+                                (n.successStatuses = [200]),
+                                (e.next = 6),
+                                this.request(n)
+                              );
+                            case 6:
+                              return (
+                                (n = e.sent),
+                                (s = n.data.Contents || []),
+                                (i = this),
+                                (s =
+                                  s &&
+                                  (s = Array.isArray(s) ? s : [s]).map(function (e) {
+                                    return {
+                                      name: e.Key,
+                                      url: i._objectUrl(e.Key),
+                                      lastModified: e.LastModified,
+                                      etag: e.ETag,
+                                      type: e.Type,
+                                      size: Number(e.Size),
+                                      storageClass: e.StorageClass,
+                                      owner: { id: e.Owner.ID, displayName: e.Owner.DisplayName }
+                                    };
+                                  })),
+                                (o =
+                                  (o = n.data.CommonPrefixes || null) &&
+                                  (o = Array.isArray(o) ? o : [o]).map(function (e) {
+                                    return e.Prefix;
+                                  })),
+                                e.abrupt('return', {
+                                  res: n.res,
+                                  objects: s,
+                                  prefixes: o,
+                                  nextMarker: n.data.NextMarker || null,
+                                  isTruncated: 'true' === n.data.IsTruncated
+                                })
+                              );
+                            case 13:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (r.listV2 = (function () {
+                var t = (0, s.default)(
+                  c.default.mark(function e(t) {
+                    var r,
+                      n,
+                      s,
+                      i,
+                      o = arguments;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                (r = 1 < o.length && void 0 !== o[1] ? o[1] : {}),
+                                (n = t['continuation-token'] || t.continuationToken) &&
+                                  (r.subres = Object.assign({ 'continuation-token': n }, r.subres)),
+                                ((n = this._objectRequestParams('GET', '', r)).query = Object.assign(
+                                  { 'list-type': 2 },
+                                  t
+                                )),
+                                delete n.query['continuation-token'],
+                                delete n.query.continuationToken,
+                                (n.xmlResponse = !0),
+                                (n.successStatuses = [200]),
+                                (e.next = 11),
+                                this.request(n)
+                              );
+                            case 11:
+                              return (
+                                (r = e.sent),
+                                (n = r.data.Contents || []),
+                                (s = this),
+                                (n =
+                                  n &&
+                                  (n = Array.isArray(n) ? n : [n]).map(function (e) {
+                                    var t = null;
+                                    return (
+                                      e.Owner && (t = { id: e.Owner.ID, displayName: e.Owner.DisplayName }),
+                                      {
+                                        name: e.Key,
+                                        url: s._objectUrl(e.Key),
+                                        lastModified: e.LastModified,
+                                        etag: e.ETag,
+                                        type: e.Type,
+                                        size: Number(e.Size),
+                                        storageClass: e.StorageClass,
+                                        owner: t
+                                      }
+                                    );
+                                  })),
+                                (i =
+                                  (i = r.data.CommonPrefixes || null) &&
+                                  (i = Array.isArray(i) ? i : [i]).map(function (e) {
+                                    return e.Prefix;
+                                  })),
+                                e.abrupt('return', {
+                                  res: r.res,
+                                  objects: n,
+                                  prefixes: i,
+                                  isTruncated: 'true' === r.data.IsTruncated,
+                                  keyCount: +r.data.KeyCount,
+                                  continuationToken: r.data.ContinuationToken || null,
+                                  nextContinuationToken: r.data.NextContinuationToken || null
+                                })
+                              );
+                            case 18:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e) {
+                  return t.apply(this, arguments);
+                };
+              })()),
+              (r.restore = (function () {
+                var t = (0, s.default)(
+                  c.default.mark(function e(t) {
+                    var r,
+                      n,
+                      s = arguments;
+                    return c.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                ((n = (n = 1 < s.length && void 0 !== s[1] ? s[1] : { type: 'Archive' }) || {}).subres =
+                                  Object.assign({ restore: '' }, n.subres)),
+                                n.versionId && (n.subres.versionId = n.versionId),
+                                (r = this._objectRequestParams('POST', t, n)),
+                                'ColdArchive' === n.type &&
+                                  ((n = {
+                                    RestoreRequest: {
+                                      Days: n.Days || 2,
+                                      JobParameters: { Tier: n.JobParameters || 'Standard' }
+                                    }
+                                  }),
+                                  (r.content = a(n, { headers: !0 })),
+                                  (r.mime = 'xml')),
+                                (r.successStatuses = [202]),
+                                (e.next = 9),
+                                this.request(r)
+                              );
+                            case 9:
+                              return (n = e.sent), e.abrupt('return', { res: n.res });
+                            case 11:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e) {
+                  return t.apply(this, arguments);
+                };
+              })()),
+              (r._objectUrl = function (e) {
+                return this._getReqUrl({ bucket: this.options.bucket, object: e });
+              }),
+              (r._objectRequestParams = function (e, t, r) {
+                if (!this.options.bucket && !this.options.cname) throw new Error('Please create a bucket first');
+                r = r || {};
+                t = {
+                  object: (t = this._objectName(t)),
+                  bucket: this.options.bucket,
+                  method: e,
+                  subres: r && r.subres,
+                  timeout: r && r.timeout,
+                  ctx: r && r.ctx
+                };
+                return r.headers && ((t.headers = {}), o(r.headers).to(t.headers)), t;
+              }),
+              (r._objectName = function (e) {
+                return e.replace(/^\/+/, '');
+              }),
+              (r._convertMetaToHeaders = function (t, r) {
+                t &&
+                  Object.keys(t).forEach(function (e) {
+                    r['x-oss-meta-'.concat(e)] = t[e];
+                  });
+              }),
+              (r._deleteFileSafe = function (r) {
+                var n = this;
+                return new Promise(function (t) {
+                  i.exists(r, function (e) {
+                    e
+                      ? i.unlink(r, function (e) {
+                          e && n.debug('unlink %j error: %s', r, e, 'error'), t();
+                        })
+                      : t();
+                  });
+                });
+              });
+          },
+          {
+            '../common/callback': 24,
+            '../common/image': 27,
+            '../common/object/asyncSignatureUrl': 31,
+            '../common/object/copyObject': 32,
+            '../common/object/delete': 33,
+            '../common/object/deleteMulti': 34,
+            '../common/object/deleteObjectTagging': 35,
+            '../common/object/generateObjectUrl': 36,
+            '../common/object/get': 37,
+            '../common/object/getACL': 38,
+            '../common/object/getBucketVersions': 39,
+            '../common/object/getObjectMeta': 40,
+            '../common/object/getObjectTagging': 41,
+            '../common/object/getObjectUrl': 42,
+            '../common/object/getSymlink': 43,
+            '../common/object/head': 44,
+            '../common/object/putACL': 45,
+            '../common/object/putObjectTagging': 46,
+            '../common/object/putSymlink': 47,
+            '../common/object/signatureUrl': 48,
+            '../common/utils/isBlob': 63,
+            '../common/utils/isBuffer': 64,
+            '../common/utils/isFile': 65,
+            '../common/utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'copy-to': 91,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.number.constructor.js': 283,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            fs: 87,
+            'merge-descriptors': 357,
+            mime: 359,
+            path: 363
+          }
+        ],
+        6: [
+          function (e, t, r) {
+            'use strict';
+            r.version = '6.18.0';
+          },
+          {}
+        ],
+        7: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.abortBucketWorm = void 0),
+                e('../utils/checkBucketName'));
+            function a() {
+              return (a = (0, i.default)(
+                s.default.mark(function e(t, r) {
+                  var n;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o.checkBucketName(t),
+                              (n = this._bucketRequestParams('DELETE', t, 'worm', r)),
+                              (e.next = 4),
+                              this.request(n)
+                            );
+                          case 4:
+                            return (n = e.sent), e.abrupt('return', { res: n.res, status: n.status });
+                          case 6:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.abortBucketWorm = function (e, t) {
+              return a.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        8: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.completeBucketWorm = void 0),
+                e('../utils/checkBucketName'));
+            function a() {
+              return (a = (0, s.default)(
+                i.default.mark(function e(t, r, n) {
+                  var s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o.checkBucketName(t),
+                              (s = this._bucketRequestParams('POST', t, { wormId: r }, n)),
+                              (e.next = 4),
+                              this.request(s)
+                            );
+                          case 4:
+                            return (s = e.sent), e.abrupt('return', { res: s.res, status: s.status });
+                          case 6:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.completeBucketWorm = function (e, t, r) {
+              return a.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        9: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              a =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.deleteBucketInventory = void 0),
+                e('../utils/checkBucketName'));
+            function i() {
+              return (i = (0, s.default)(
+                o.default.mark(function e(t, r) {
+                  var n,
+                    s,
+                    i = arguments;
+                  return o.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (s = 2 < i.length && void 0 !== i[2] ? i[2] : {}),
+                              (n = Object.assign({ inventory: '', inventoryId: r }, s.subres)),
+                              a.checkBucketName(t),
+                              ((n = this._bucketRequestParams('DELETE', t, n, s)).successStatuses = [204]),
+                              (e.next = 7),
+                              this.request(n)
+                            );
+                          case 7:
+                            return (s = e.sent), e.abrupt('return', { status: s.status, res: s.res });
+                          case 9:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.deleteBucketInventory = function (e, t) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        10: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o = e('../utils/checkBucketName').checkBucketName;
+            r.deleteBucketLifecycle = (function () {
+              var r = (0, i.default)(
+                s.default.mark(function e(t, r) {
+                  var n;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o(t),
+                              ((n = this._bucketRequestParams('DELETE', t, 'lifecycle', r)).successStatuses = [204]),
+                              (e.next = 5),
+                              this.request(n)
+                            );
+                          case 5:
+                            return (n = e.sent), e.abrupt('return', { res: n.res });
+                          case 7:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        11: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o = e('../utils/checkBucketName').checkBucketName;
+            r.deleteBucketWebsite = (function () {
+              var r = (0, i.default)(
+                s.default.mark(function e(t, r) {
+                  var n;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o(t),
+                              ((n = this._bucketRequestParams('DELETE', t, 'website', r)).successStatuses = [204]),
+                              (e.next = 5),
+                              this.request(n)
+                            );
+                          case 5:
+                            return (n = e.sent), e.abrupt('return', { res: n.res });
+                          case 7:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        12: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              c =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.extendBucketWorm = void 0),
+                e('../utils/checkBucketName')),
+              l = e('../utils/obj2xml');
+            function i() {
+              return (i = (0, s.default)(
+                a.default.mark(function e(t, r, n, s) {
+                  var i, o;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              c.checkBucketName(t),
+                              (i = this._bucketRequestParams('POST', t, { wormExtend: '', wormId: r }, s)),
+                              (o = { ExtendWormConfiguration: { RetentionPeriodInDays: n } }),
+                              (i.mime = 'xml'),
+                              (i.content = l.obj2xml(o, { headers: !0 })),
+                              (i.successStatuses = [200]),
+                              (e.next = 8),
+                              this.request(i)
+                            );
+                          case 8:
+                            return (o = e.sent), e.abrupt('return', { res: o.res, status: o.status });
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.extendBucketWorm = function (e, t, r, n) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        13: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              a =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.getBucketInventory = void 0),
+                e('../utils/checkBucketName')),
+              c = e('../utils/formatInventoryConfig');
+            function i() {
+              return (i = (0, s.default)(
+                o.default.mark(function e(t, r) {
+                  var n,
+                    s,
+                    i = arguments;
+                  return o.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (s = 2 < i.length && void 0 !== i[2] ? i[2] : {}),
+                              (n = Object.assign({ inventory: '', inventoryId: r }, s.subres)),
+                              a.checkBucketName(t),
+                              ((n = this._bucketRequestParams('GET', t, n, s)).successStatuses = [200]),
+                              (n.xmlResponse = !0),
+                              (e.next = 8),
+                              this.request(n)
+                            );
+                          case 8:
+                            return (
+                              (s = e.sent),
+                              e.abrupt('return', {
+                                status: s.status,
+                                res: s.res,
+                                inventory: c.formatInventoryConfig(s.data)
+                              })
+                            );
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.getBucketInventory = function (e, t) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/formatInventoryConfig': 59,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        14: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.array.map.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              o = e('../utils/checkBucketName').checkBucketName,
+              a = e('../utils/isArray').isArray,
+              c = e('../utils/formatObjKey').formatObjKey;
+            r.getBucketLifecycle = (function () {
+              var r = (0, s.default)(
+                i.default.mark(function e(t, r) {
+                  var n, s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o(t),
+                              ((n = this._bucketRequestParams('GET', t, 'lifecycle', r)).successStatuses = [200]),
+                              (n.xmlResponse = !0),
+                              (e.next = 6),
+                              this.request(n)
+                            );
+                          case 6:
+                            return (
+                              (n = e.sent),
+                              (s =
+                                (s = n.data.Rule || null) &&
+                                (s = a(s) ? s : [s]).map(function (e) {
+                                  return (
+                                    e.ID && ((e.id = e.ID), delete e.ID),
+                                    e.Tag && !a(e.Tag) && (e.Tag = [e.Tag]),
+                                    c(e, 'firstLowerCase')
+                                  );
+                                })),
+                              e.abrupt('return', { rules: s, res: n.res })
+                            );
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/formatObjKey': 60,
+            '../utils/isArray': 62,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.map.js': 277
+          }
+        ],
+        15: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o = e('../utils/checkBucketName').checkBucketName;
+            r.getBucketVersioning = (function () {
+              var r = (0, s.default)(
+                i.default.mark(function e(t, r) {
+                  var n, s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o(t),
+                              ((n = this._bucketRequestParams('GET', t, 'versioning', r)).xmlResponse = !0),
+                              (n.successStatuses = [200]),
+                              (e.next = 6),
+                              this.request(n)
+                            );
+                          case 6:
+                            return (
+                              (n = e.sent),
+                              (s = n.data.Status),
+                              e.abrupt('return', { status: n.status, versionStatus: s, res: n.res })
+                            );
+                          case 9:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        16: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              o = e('../utils/checkBucketName').checkBucketName,
+              a = e('../utils/isObject').isObject;
+            r.getBucketWebsite = (function () {
+              var r = (0, s.default)(
+                i.default.mark(function e(t, r) {
+                  var n, s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o(t),
+                              ((n = this._bucketRequestParams('GET', t, 'website', r)).successStatuses = [200]),
+                              (n.xmlResponse = !0),
+                              (e.next = 6),
+                              this.request(n)
+                            );
+                          case 6:
+                            return (
+                              (n = e.sent),
+                              (s = []),
+                              n.data.RoutingRules &&
+                                n.data.RoutingRules.RoutingRule &&
+                                (s = a(n.data.RoutingRules.RoutingRule)
+                                  ? [n.data.RoutingRules.RoutingRule]
+                                  : n.data.RoutingRules.RoutingRule),
+                              e.abrupt('return', {
+                                index: (n.data.IndexDocument && n.data.IndexDocument.Suffix) || '',
+                                supportSubDir: (n.data.IndexDocument && n.data.IndexDocument.SupportSubDir) || 'false',
+                                type: n.data.IndexDocument && n.data.IndexDocument.Type,
+                                routingRules: s,
+                                error: (n.data.ErrorDocument && n.data.ErrorDocument.Key) || null,
+                                res: n.res
+                              })
+                            );
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/isObject': 68,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        17: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              o =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.getBucketWorm = void 0),
+                e('../utils/checkBucketName')),
+              a = e('../utils/dataFix');
+            function c() {
+              return (c = (0, i.default)(
+                s.default.mark(function e(t, r) {
+                  var n;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              o.checkBucketName(t),
+                              ((n = this._bucketRequestParams('GET', t, 'worm', r)).successStatuses = [200]),
+                              (n.xmlResponse = !0),
+                              (e.next = 6),
+                              this.request(n)
+                            );
+                          case 6:
+                            return (
+                              (n = e.sent),
+                              a.dataFix(n.data, { lowerFirst: !0, rename: { RetentionPeriodInDays: 'days' } }),
+                              e.abrupt(
+                                'return',
+                                Object.assign(Object.assign({}, n.data), { res: n.res, status: n.status })
+                              )
+                            );
+                          case 9:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.getBucketWorm = function (e, t) {
+              return c.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/dataFix': 56,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        18: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              a =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.initiateBucketWorm = void 0),
+                e('../utils/obj2xml')),
+              c = e('../utils/checkBucketName');
+            function i() {
+              return (i = (0, s.default)(
+                o.default.mark(function e(t, r, n) {
+                  var s, i;
+                  return o.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              c.checkBucketName(t),
+                              (s = this._bucketRequestParams('POST', t, 'worm', n)),
+                              (i = { InitiateWormConfiguration: { RetentionPeriodInDays: r } }),
+                              (s.mime = 'xml'),
+                              (s.content = a.obj2xml(i, { headers: !0 })),
+                              (s.successStatuses = [200]),
+                              (e.next = 8),
+                              this.request(s)
+                            );
+                          case 8:
+                            return (
+                              (i = e.sent),
+                              e.abrupt('return', {
+                                res: i.res,
+                                wormId: i.res.headers['x-oss-worm-id'],
+                                status: i.status
+                              })
+                            );
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.initiateBucketWorm = function (e, t, r) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        19: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              c =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.listBucketInventory = void 0),
+                e('../utils/checkBucketName')),
+              l = e('../utils/formatInventoryConfig');
+            function i() {
+              return (i = (0, s.default)(
+                a.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s,
+                    i,
+                    o = arguments;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (n = (r = 1 < o.length && void 0 !== o[1] ? o[1] : {}).continuationToken),
+                              (n = Object.assign({ inventory: '' }, n && { 'continuation-token': n }, r.subres)),
+                              c.checkBucketName(t),
+                              ((n = this._bucketRequestParams('GET', t, n, r)).successStatuses = [200]),
+                              (n.xmlResponse = !0),
+                              (e.next = 9),
+                              this.request(n)
+                            );
+                          case 9:
+                            return (
+                              (r = e.sent),
+                              (n = r.data),
+                              (s = r.res),
+                              (i = r.status),
+                              e.abrupt('return', {
+                                isTruncated: 'true' === n.IsTruncated,
+                                nextContinuationToken: n.NextContinuationToken,
+                                inventoryList: l.formatInventoryConfig(n.InventoryConfiguration, !0),
+                                status: i,
+                                res: s
+                              })
+                            );
+                          case 12:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.listBucketInventory = function (e) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/formatInventoryConfig': 59,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        20: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              u = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.array.concat.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              p =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.putBucketInventory = void 0),
+                e('../utils/checkBucketName')),
+              f = e('../utils/obj2xml');
+            function i() {
+              return (i = (0, s.default)(
+                u.default.mark(function e(t, r) {
+                  var n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c,
+                    l = arguments;
+                  return u.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (n = 2 < l.length && void 0 !== l[2] ? l[2] : {}),
+                              (s = Object.assign({ inventory: '', inventoryId: r.id }, n.subres)),
+                              p.checkBucketName(t),
+                              (o = r.OSSBucketDestination),
+                              (c = r.optionalFields),
+                              (a = r.includedObjectVersions),
+                              (i = 'acs:ram::'.concat(o.accountId, ':role/')),
+                              (i = {
+                                InventoryConfiguration: {
+                                  Id: r.id,
+                                  IsEnabled: r.isEnabled,
+                                  Filter: { Prefix: r.prefix || '' },
+                                  Destination: {
+                                    OSSBucketDestination: {
+                                      Format: o.format,
+                                      AccountId: o.accountId,
+                                      RoleArn: ''.concat(i).concat(o.rolename),
+                                      Bucket: ''.concat('acs:oss:::').concat(o.bucket),
+                                      Prefix: o.prefix || '',
+                                      Encryption: o.encryption || ''
+                                    }
+                                  },
+                                  Schedule: { Frequency: r.frequency },
+                                  IncludedObjectVersions: a,
+                                  OptionalFields: { Field: (null == c ? void 0 : c.field) || [] }
+                                }
+                              }),
+                              (o = f.obj2xml(i, { headers: !0, firstUpperCase: !0 })),
+                              ((a = this._bucketRequestParams('PUT', t, s, n)).successStatuses = [200]),
+                              (a.mime = 'xml'),
+                              (a.content = o),
+                              (e.next = 14),
+                              this.request(a)
+                            );
+                          case 14:
+                            return (c = e.sent), e.abrupt('return', { status: c.status, res: c.res });
+                          case 16:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            r.putBucketInventory = function (e, t) {
+              return i.apply(this, arguments);
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        21: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.array.includes.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              c = e('../utils/checkBucketName').checkBucketName,
+              l = e('../utils/isArray').isArray,
+              u = e('../utils/deepCopy').deepCopy,
+              p = e('../utils/isObject').isObject,
+              f = e('../utils/obj2xml').obj2xml,
+              d = e('../utils/checkObjectTag').checkObjectTag,
+              h = e('../utils/getStrBytesCount').getStrBytesCount;
+            function m(e, t) {
+              var r = e.days,
+                e = e.createdBeforeDate;
+              if (!r && !e) throw new Error(''.concat(t, ' must includes days or createdBeforeDate'));
+              if (r && !/^[1-9][0-9]*$/.test(r)) throw new Error('days must be a positive integer');
+              if (e && !/\d{4}-\d{2}-\d{2}T00:00:00.000Z/.test(e))
+                throw new Error('createdBeforeDate must be date and conform to iso8601 format');
+            }
+            r.putBucketLifecycle = (function () {
+              var n = (0, s.default)(
+                a.default.mark(function e(t, r, n) {
+                  var s, i, o;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if ((c(t), l(r))) {
+                              e.next = 3;
+                              break;
+                            }
+                            throw new Error('rules must be Array');
+                          case 3:
+                            return (
+                              (s = this._bucketRequestParams('PUT', t, 'lifecycle', n)),
+                              (o = { LifecycleConfiguration: { Rule: (i = []) } }),
+                              r.forEach(function (e) {
+                                var t = e,
+                                  t =
+                                    (t.days && (t.expiration = { days: t.days }),
+                                    t.date && (t.expiration = { createdBeforeDate: t.date }),
+                                    e);
+                                if (t.id && 255 < h(t.id)) throw new Error('ID is composed of 255 bytes at most');
+                                if (void 0 === t.prefix) throw new Error('Rule must includes prefix');
+                                if (!['Enabled', 'Disabled'].includes(t.status))
+                                  throw new Error('Status must be  Enabled or Disabled');
+                                if (t.transition) {
+                                  if (!['IA', 'Archive'].includes(t.transition.storageClass))
+                                    throw new Error('StorageClass must be  IA or Archive');
+                                  m(t.transition, 'Transition');
+                                }
+                                if (t.expiration)
+                                  if (t.expiration.expiredObjectDeleteMarker) {
+                                    if (t.expiration.days || t.expiration.createdBeforeDate)
+                                      throw new Error(
+                                        'expiredObjectDeleteMarker cannot be used with days or createdBeforeDate'
+                                      );
+                                  } else m(t.expiration, 'Expiration');
+                                if (
+                                  (t.abortMultipartUpload && m(t.abortMultipartUpload, 'AbortMultipartUpload'),
+                                  !(
+                                    t.expiration ||
+                                    t.abortMultipartUpload ||
+                                    t.transition ||
+                                    t.noncurrentVersionTransition
+                                  ))
+                                )
+                                  throw new Error(
+                                    'Rule must includes expiration or abortMultipartUpload or transition or noncurrentVersionTransition'
+                                  );
+                                if (t.tag) {
+                                  if (t.abortMultipartUpload)
+                                    throw new Error('Tag cannot be used with abortMultipartUpload');
+                                  !(function (e) {
+                                    if (!l(e) && !p(e)) throw new Error('tag must be Object or Array');
+                                    e = p(e) ? [e] : e;
+                                    var t = {};
+                                    u(e).forEach(function (e) {
+                                      t[e.key] = e.value;
+                                    }),
+                                      d(t);
+                                  })(t.tag);
+                                }
+                                e.id && ((e.ID = e.id), delete e.id), i.push(e);
+                              }),
+                              (o = f(o, { headers: !0, firstUpperCase: !0 })),
+                              (s.content = o),
+                              (s.mime = 'xml'),
+                              (s.successStatuses = [200]),
+                              (e.next = 13),
+                              this.request(s)
+                            );
+                          case 13:
+                            return (o = e.sent), e.abrupt('return', { res: o.res });
+                          case 15:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r) {
+                return n.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/checkObjectTag': 53,
+            '../utils/deepCopy': 57,
+            '../utils/getStrBytesCount': 61,
+            '../utils/isArray': 62,
+            '../utils/isObject': 68,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        22: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.array.includes.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              c = e('../utils/checkBucketName').checkBucketName,
+              l = e('../utils/obj2xml').obj2xml;
+            r.putBucketVersioning = (function () {
+              var r = (0, s.default)(
+                a.default.mark(function e(t, r) {
+                  var n,
+                    s,
+                    i,
+                    o = arguments;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if (
+                              ((n = 2 < o.length && void 0 !== o[2] ? o[2] : {}),
+                              c(t),
+                              ['Enabled', 'Suspended'].includes(r))
+                            ) {
+                              e.next = 4;
+                              break;
+                            }
+                            throw new Error('status must be Enabled or Suspended');
+                          case 4:
+                            return (
+                              (s = this._bucketRequestParams('PUT', t, 'versioning', n)),
+                              (i = { VersioningConfiguration: { Status: r } }),
+                              (s.mime = 'xml'),
+                              (s.content = l(i, { headers: !0 })),
+                              (e.next = 10),
+                              this.request(s)
+                            );
+                          case 10:
+                            return (i = e.sent), e.abrupt('return', { res: i.res, status: i.status });
+                          case 12:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.includes.js': 274
+          }
+        ],
+        23: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              c = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              l = e('../utils/checkBucketName').checkBucketName,
+              u = e('../utils/obj2xml').obj2xml,
+              p = e('../utils/isArray').isArray;
+            r.putBucketWebsite = (function () {
+              var t = (0, s.default)(
+                c.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a = arguments;
+                  return c.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if (
+                              ((r = 1 < a.length && void 0 !== a[1] ? a[1] : {}),
+                              (n = 2 < a.length ? a[2] : void 0),
+                              l(t),
+                              (n = this._bucketRequestParams('PUT', t, 'website', n)),
+                              (o = { Suffix: r.index || 'index.html' }),
+                              (i = { WebsiteConfiguration: (s = { IndexDocument: o }) }),
+                              r.supportSubDir && (o.SupportSubDir = r.supportSubDir),
+                              r.type && (o.Type = r.type),
+                              r.error && (s.ErrorDocument = { Key: r.error }),
+                              void 0 === r.routingRules)
+                            ) {
+                              e.next = 14;
+                              break;
+                            }
+                            if (p(r.routingRules)) {
+                              e.next = 13;
+                              break;
+                            }
+                            throw new Error('RoutingRules must be Array');
+                          case 13:
+                            s.RoutingRules = { RoutingRule: r.routingRules };
+                          case 14:
+                            return (
+                              (i = u(i)),
+                              (n.content = i),
+                              (n.mime = 'xml'),
+                              (n.successStatuses = [200]),
+                              (e.next = 20),
+                              this.request(n)
+                            );
+                          case 20:
+                            return (o = e.sent), e.abrupt('return', { res: o.res });
+                          case 22:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/isArray': 62,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79
+          }
+        ],
+        24: [
+          function (e, t, r) {
+            !function (s) {
+              !function () {
+                'use strict';
+                e('core-js/modules/es.object.to-string.js'),
+                  e('core-js/modules/es.regexp.to-string.js'),
+                  e('core-js/modules/web.dom-collections.for-each.js'),
+                  e('core-js/modules/es.object.keys.js'),
+                  (r.encodeCallback = function (e, t) {
+                    var r, n;
+                    (e.headers = e.headers || {}),
+                      Object.prototype.hasOwnProperty.call(e.headers, 'x-oss-callback') ||
+                        (t.callback &&
+                          ((r = { callbackUrl: encodeURI(t.callback.url), callbackBody: t.callback.body }),
+                          t.callback.host && (r.callbackHost = t.callback.host),
+                          t.callback.contentType && (r.callbackBodyType = t.callback.contentType),
+                          (r = s.from(JSON.stringify(r)).toString('base64')),
+                          (e.headers['x-oss-callback'] = r),
+                          t.callback.customValue &&
+                            ((n = {}),
+                            Object.keys(t.callback.customValue).forEach(function (e) {
+                              n['x:'.concat(e)] = t.callback.customValue[e].toString();
+                            }),
+                            (e.headers['x-oss-callback-var'] = s.from(JSON.stringify(n)).toString('base64')))));
+                  });
+              }.call(this);
+            }.call(this, e('buffer').Buffer);
+          },
+          {
+            buffer: 89,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        25: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.concat.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.string.replace.js'),
+              e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js');
+            var n = function (e) {
+                return e && e.__esModule ? e : { default: e };
+              },
+              s = (Object.defineProperty(r, '__esModule', { value: !0 }), (r.getReqUrl = void 0), n(e('copy-to'))),
+              i = n(e('url')),
+              o = n(e('merge-descriptors')),
+              a = n(e('is-type-of')),
+              c = e('../utils/isIP'),
+              l = e('../utils/checkConfigValid');
+            r.getReqUrl = function (e) {
+              var t,
+                r = {},
+                n = this.options.cname,
+                n =
+                  (l.checkConfigValid(this.options.endpoint, 'endpoint'),
+                  s.default(this.options.endpoint, !1).to(r),
+                  !e.bucket ||
+                    n ||
+                    c.isIP(r.hostname) ||
+                    this.options.sldEnable ||
+                    (r.host = ''.concat(e.bucket, '.').concat(r.host)),
+                  '/'),
+                n =
+                  (e.bucket && this.options.sldEnable && (n += ''.concat(e.bucket, '/')),
+                  e.object && (n += this._escape(e.object).replace(/\+/g, '%2B')),
+                  (r.pathname = n),
+                  {});
+              return (
+                e.query && o.default(n, e.query),
+                e.subres &&
+                  ((t = {}),
+                  a.default.string(e.subres)
+                    ? (t[e.subres] = '')
+                    : a.default.array(e.subres)
+                    ? e.subres.forEach(function (e) {
+                        t[e] = '';
+                      })
+                    : (t = e.subres),
+                  o.default(n, t)),
+                (r.query = n),
+                i.default.format(r)
+              );
+            };
+          },
+          {
+            '../utils/checkConfigValid': 52,
+            '../utils/isIP': 67,
+            'copy-to': 91,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            'is-type-of': 440,
+            'merge-descriptors': 357,
+            url: 446
+          }
+        ],
+        26: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.concat.js'),
+              e('core-js/modules/es.object.assign.js'),
+              e('core-js/modules/es.string.trim.js');
+            var n = e('humanize-ms'),
+              s = e('url'),
+              i = e('../utils/checkBucketName').checkBucketName,
+              o = e('../utils/setRegion').setRegion,
+              a = e('../utils/checkConfigValid').checkConfigValid;
+            t.exports = function (e) {
+              if (!e || !e.accessKeyId || !e.accessKeySecret) throw new Error('require accessKeyId, accessKeySecret');
+              !e.stsToken ||
+                e.refreshSTSToken ||
+                e.refreshSTSTokenInterval ||
+                console.warn(
+                  "It's recommended to set 'refreshSTSToken' and 'refreshSTSTokenInterval' to refresh stsToken\u3001accessKeyId\u3001accessKeySecret automatically when sts token has expired"
+                ),
+                e.bucket && i(e.bucket);
+              e = Object.assign(
+                {
+                  region: 'oss-cn-hangzhou',
+                  internal: !1,
+                  secure: !1,
+                  timeout: 6e4,
+                  bucket: null,
+                  endpoint: null,
+                  cname: !1,
+                  isRequestPay: !1,
+                  sldEnable: !1,
+                  headerEncoding: 'utf-8',
+                  refreshSTSToken: null,
+                  refreshSTSTokenInterval: 3e5,
+                  retryMax: 0
+                },
+                e
+              );
+              if (
+                ((e.accessKeyId = e.accessKeyId.trim()),
+                (e.accessKeySecret = e.accessKeySecret.trim()),
+                e.timeout && (e.timeout = n(e.timeout)),
+                e.endpoint)
+              )
+                e.endpoint = (function (e, t) {
+                  a(e, 'endpoint');
+                  var r = s.parse(e);
+                  if (
+                    'http:' !== (r = r.protocol ? r : s.parse('http'.concat(t ? 's' : '', '://').concat(e))).protocol &&
+                    'https:' !== r.protocol
+                  )
+                    throw new Error('Endpoint protocol must be http or https.');
+                  return r;
+                })(e.endpoint, e.secure);
+              else {
+                if (!e.region) throw new Error('require options.endpoint or options.region');
+                e.endpoint = o(e.region, e.internal, e.secure);
+              }
+              return (e.inited = !0), e;
+            };
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '../utils/checkConfigValid': 52,
+            '../utils/setRegion': 73,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.string.trim.js': 307,
+            'humanize-ms': 345,
+            url: 446
+          }
+        ],
+        27: [
+          function (e, t, r) {
+            'use strict';
+            e('merge-descriptors')(r, e('./processObjectSave'));
+          },
+          { './processObjectSave': 28, 'merge-descriptors': 357 }
+        ],
+        28: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.array.concat.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              c = e('../utils/checkBucketName').checkBucketName,
+              l = e('querystring'),
+              u = e('js-base64').Base64.encode;
+            function p(e, t) {
+              if (!e) throw new Error(''.concat(t, ' is required'));
+              if ('string' != typeof e) throw new Error(''.concat(t, ' must be String'));
+            }
+            r.processObjectSave = (function () {
+              var s = (0, i.default)(
+                a.default.mark(function e(t, r, n, s) {
+                  var i, o;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              p(t, 'sourceObject'),
+                              p(r, 'targetObject'),
+                              p(n, 'process'),
+                              (r = this._objectName(r)),
+                              s && c(s),
+                              (i = this._objectRequestParams('POST', t, { subres: 'x-oss-process' })),
+                              (o = s ? ',b_'.concat(u(s)) : ''),
+                              (r = u(r)),
+                              (o = { 'x-oss-process': ''.concat(n, '|sys/saveas,o_').concat(r).concat(o) }),
+                              (i.content = l.stringify(o)),
+                              (e.next = 12),
+                              this.request(i)
+                            );
+                          case 12:
+                            return (o = e.sent), e.abrupt('return', { res: o.res, status: o.res.status });
+                          case 14:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r, n) {
+                return s.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.concat.js': 269,
+            'js-base64': 356,
+            querystring: 370
+          }
+        ],
+        29: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              b = n(e('@babel/runtime/regenerator')),
+              g =
+                (e('core-js/modules/es.array.concat.js'),
+                e('core-js/modules/es.function.name.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/es.promise.js'),
+                e('core-js/modules/es.array.from.js'),
+                e('core-js/modules/es.string.iterator.js'),
+                e('core-js/modules/es.array.map.js'),
+                e('core-js/modules/es.array.filter.js'),
+                e('core-js/modules/es.array.find.js'),
+                e('core-js/modules/es.regexp.to-string.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              v = e('debug')('ali-oss:multipart-copy'),
+              j = e('copy-to'),
+              n = r;
+            (n.uploadPartCopy = (function () {
+              var i = (0, g.default)(
+                b.default.mark(function e(t, r, n, s, i) {
+                  var o,
+                    a,
+                    c = arguments;
+                  return b.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((a = 5 < c.length && void 0 !== c[5] ? c[5] : {}).headers = a.headers || {}),
+                              (o = a.versionId || (a.subres && a.subres.versionId) || null),
+                              (o = o
+                                ? '/'
+                                    .concat(i.sourceBucketName, '/')
+                                    .concat(encodeURIComponent(i.sourceKey), '?versionId=')
+                                    .concat(o)
+                                : '/'.concat(i.sourceBucketName, '/').concat(encodeURIComponent(i.sourceKey))),
+                              (a.headers['x-oss-copy-source'] = o),
+                              s && (a.headers['x-oss-copy-source-range'] = 'bytes='.concat(s)),
+                              (a.subres = { partNumber: n, uploadId: r }),
+                              ((o = this._objectRequestParams('PUT', t, a)).mime = a.mime),
+                              (o.successStatuses = [200]),
+                              (e.next = 12),
+                              this.request(o)
+                            );
+                          case 12:
+                            return (a = e.sent), e.abrupt('return', { name: t, etag: a.res.headers.etag, res: a.res });
+                          case 14:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r, n, s) {
+                return i.apply(this, arguments);
+              };
+            })()),
+              (n.multipartUploadCopy = (function () {
+                var r = (0, g.default)(
+                  b.default.mark(function e(t, r) {
+                    var n,
+                      s,
+                      i,
+                      o,
+                      a,
+                      c,
+                      l,
+                      u = arguments;
+                    return b.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (
+                                (n = 2 < u.length && void 0 !== u[2] ? u[2] : {}),
+                                this.resetCancelFlag(),
+                                (s = n.versionId),
+                                (s = { versionId: void 0 === s ? null : s }),
+                                (e.next = 6),
+                                this._getObjectMeta(r.sourceBucketName, r.sourceKey, s)
+                              );
+                            case 6:
+                              if (
+                                ((s = e.sent),
+                                (a = s.res.headers['content-length']),
+                                (r.startOffset = r.startOffset || 0),
+                                (r.endOffset = r.endOffset || a),
+                                n.checkpoint && n.checkpoint.uploadId)
+                              )
+                                return (e.next = 13), this._resumeMultipartCopy(n.checkpoint, r, n);
+                              e.next = 14;
+                              break;
+                            case 13:
+                              return e.abrupt('return', e.sent);
+                            case 14:
+                              if (((i = 102400), (o = r.endOffset - r.startOffset) < i))
+                                throw new Error('copySize must not be smaller than '.concat(i));
+                              e.next = 18;
+                              break;
+                            case 18:
+                              if (n.partSize && n.partSize < i)
+                                throw new Error('partSize must not be smaller than '.concat(i));
+                              e.next = 20;
+                              break;
+                            case 20:
+                              return (e.next = 22), this.initMultipartUpload(t, n);
+                            case 22:
+                              if (
+                                ((a = e.sent),
+                                (c = a.uploadId),
+                                (l = this._getPartSize(o, n.partSize)),
+                                (l = { name: t, copySize: o, partSize: l, uploadId: c, doneParts: [] }),
+                                n && n.progress)
+                              )
+                                return (e.next = 29), n.progress(0, l, a.res);
+                              e.next = 29;
+                              break;
+                            case 29:
+                              return (e.next = 31), this._resumeMultipartCopy(l, r, n);
+                            case 31:
+                              return e.abrupt('return', e.sent);
+                            case 32:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t) {
+                  return r.apply(this, arguments);
+                };
+              })()),
+              (n._resumeMultipartCopy = (function () {
+                var n = (0, g.default)(
+                  b.default.mark(function e(c, t, l) {
+                    var u, p, f, d, h, m, r, n, s, i, o, a, y;
+                    return b.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              if (this.isCancel()) throw this._makeCancelEvent();
+                              e.next = 2;
+                              break;
+                            case 2:
+                              if (
+                                ((s = l.versionId),
+                                (i = { versionId: (s = void 0 === s ? null : s) }),
+                                (r = c.copySize),
+                                (o = c.partSize),
+                                (u = c.uploadId),
+                                (p = c.doneParts),
+                                (f = c.name),
+                                (d = this._divideMultipartCopyParts(r, o, t.startOffset)),
+                                (h = d.length),
+                                (m = { headers: {} }),
+                                l.copyheaders && j(l.copyheaders).to(m.headers),
+                                s && j(i).to(m),
+                                (r = function (i, o, a) {
+                                  return new Promise(
+                                    (function () {
+                                      var r = (0, g.default)(
+                                        b.default.mark(function e(t, r) {
+                                          var n, s;
+                                          return b.default.wrap(
+                                            function (e) {
+                                              for (;;)
+                                                switch ((e.prev = e.next)) {
+                                                  case 0:
+                                                    if (((e.prev = 0), i.isCancel())) {
+                                                      e.next = 22;
+                                                      break;
+                                                    }
+                                                    return (
+                                                      (n = d[o - 1]),
+                                                      (n = ''.concat(n.start, '-').concat(n.end - 1)),
+                                                      (e.prev = 4),
+                                                      (e.next = 7),
+                                                      i.uploadPartCopy(f, u, o, n, a, m)
+                                                    );
+                                                  case 7:
+                                                    (s = e.sent), (e.next = 15);
+                                                    break;
+                                                  case 10:
+                                                    if (((e.prev = 10), (e.t0 = e.catch(4)), 404 === e.t0.status))
+                                                      throw i._makeAbortEvent();
+                                                    e.next = 14;
+                                                    break;
+                                                  case 14:
+                                                    throw e.t0;
+                                                  case 15:
+                                                    if (i.isCancel()) {
+                                                      e.next = 22;
+                                                      break;
+                                                    }
+                                                    if (
+                                                      (v('content-range '.concat(s.res.headers['content-range'])),
+                                                      p.push({ number: o, etag: s.res.headers.etag }),
+                                                      (c.doneParts = p),
+                                                      l && l.progress)
+                                                    )
+                                                      return (e.next = 22), l.progress(p.length / h, c, s.res);
+                                                    e.next = 22;
+                                                    break;
+                                                  case 22:
+                                                    t(), (e.next = 29);
+                                                    break;
+                                                  case 25:
+                                                    (e.prev = 25), (e.t1 = e.catch(0)), (e.t1.partNum = o), r(e.t1);
+                                                  case 29:
+                                                  case 'end':
+                                                    return e.stop();
+                                                }
+                                            },
+                                            e,
+                                            null,
+                                            [
+                                              [0, 25],
+                                              [4, 10]
+                                            ]
+                                          );
+                                        })
+                                      );
+                                      return function (e, t) {
+                                        return r.apply(this, arguments);
+                                      };
+                                    })()
+                                  );
+                                }),
+                                (o = Array.from(new Array(h), function (e, t) {
+                                  return t + 1;
+                                })),
+                                (n = p.map(function (e) {
+                                  return e.number;
+                                })),
+                                (s = o.filter(function (e) {
+                                  return n.indexOf(e) < 0;
+                                })),
+                                (i = l.parallel || 5),
+                                !this.checkBrowserAndVersion('Internet Explorer', '10') && 1 !== i)
+                              ) {
+                                e.next = 28;
+                                break;
+                              }
+                              o = 0;
+                            case 18:
+                              if (!(o < s.length)) {
+                                e.next = 26;
+                                break;
+                              }
+                              if (this.isCancel()) throw this._makeCancelEvent();
+                              e.next = 21;
+                              break;
+                            case 21:
+                              return (e.next = 23), r(this, s[o], t);
+                            case 23:
+                              o++, (e.next = 18);
+                              break;
+                            case 26:
+                              e.next = 40;
+                              break;
+                            case 28:
+                              return (e.next = 30), this._parallelNode(s, i, r, t);
+                            case 30:
+                              if (
+                                ((a = e.sent),
+                                (y = a.find(function (e) {
+                                  return 'abort' === e.name;
+                                })))
+                              )
+                                throw y;
+                              e.next = 34;
+                              break;
+                            case 34:
+                              if (this.isCancel()) throw this._makeCancelEvent();
+                              e.next = 36;
+                              break;
+                            case 36:
+                              if (a && 0 < a.length)
+                                throw (
+                                  (((y = a[0]).message = 'Failed to copy some parts with error: '
+                                    .concat(y.toString(), ' part_num: ')
+                                    .concat(y.partNum)),
+                                  y)
+                                );
+                              e.next = 40;
+                              break;
+                            case 40:
+                              return (e.next = 42), this.completeMultipartUpload(f, u, p, l);
+                            case 42:
+                              return e.abrupt('return', e.sent);
+                            case 43:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })()),
+              (n._divideMultipartCopyParts = function (e, t, r) {
+                for (var n = Math.ceil(e / t), s = [], i = 0; i < n; i++) {
+                  var o = t * i + r,
+                    a = Math.min(o + t, e + r);
+                  s.push({ start: o, end: a });
+                }
+                return s;
+              }),
+              (n._getObjectMeta = (function () {
+                var n = (0, g.default)(
+                  b.default.mark(function e(t, r, n) {
+                    var s, i;
+                    return b.default.wrap(
+                      function (e) {
+                        for (;;)
+                          switch ((e.prev = e.next)) {
+                            case 0:
+                              return (s = this.getBucket()), this.setBucket(t), (e.next = 4), this.head(r, n);
+                            case 4:
+                              return (i = e.sent), this.setBucket(s), e.abrupt('return', i);
+                            case 7:
+                            case 'end':
+                              return e.stop();
+                          }
+                      },
+                      e,
+                      this
+                    );
+                  })
+                );
+                return function (e, t, r) {
+                  return n.apply(this, arguments);
+                };
+              })());
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'copy-to': 91,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.filter.js': 271,
+            'core-js/modules/es.array.find.js': 272,
+            'core-js/modules/es.array.from.js': 273,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.iterator.js': 302,
+            debug: 439
+          }
+        ],
+        30: [
+          function (r, e, i) {
+            !function (p) {
+              !function () {
+                'use strict';
+                r('core-js/modules/es.object.keys.js'),
+                  r('core-js/modules/es.symbol.js'),
+                  r('core-js/modules/es.object.get-own-property-descriptor.js'),
+                  r('core-js/modules/web.dom-collections.for-each.js'),
+                  r('core-js/modules/es.object.get-own-property-descriptors.js');
+                var e = r('@babel/runtime/helpers/interopRequireDefault'),
+                  f = e(r('@babel/runtime/regenerator')),
+                  n =
+                    (r('core-js/modules/es.array.map.js'),
+                    r('core-js/modules/es.array.filter.js'),
+                    r('core-js/modules/es.object.to-string.js'),
+                    r('core-js/modules/es.array.sort.js'),
+                    r('core-js/modules/es.array.concat.js'),
+                    r('core-js/modules/es.regexp.to-string.js'),
+                    e(r('@babel/runtime/helpers/defineProperty'))),
+                  t = e(r('@babel/runtime/helpers/asyncToGenerator'));
+                function s(t, e) {
+                  var r,
+                    n = Object.keys(t);
+                  return (
+                    Object.getOwnPropertySymbols &&
+                      ((r = Object.getOwnPropertySymbols(t)),
+                      e &&
+                        (r = r.filter(function (e) {
+                          return Object.getOwnPropertyDescriptor(t, e).enumerable;
+                        })),
+                      n.push.apply(n, r)),
+                    n
+                  );
+                }
+                function l(t) {
+                  for (var e = 1; e < arguments.length; e++) {
+                    var r = null != arguments[e] ? arguments[e] : {};
+                    e % 2
+                      ? s(Object(r), !0).forEach(function (e) {
+                          (0, n.default)(t, e, r[e]);
+                        })
+                      : Object.getOwnPropertyDescriptors
+                      ? Object.defineProperties(t, Object.getOwnPropertyDescriptors(r))
+                      : s(Object(r)).forEach(function (e) {
+                          Object.defineProperty(t, e, Object.getOwnPropertyDescriptor(r, e));
+                        });
+                  }
+                  return t;
+                }
+                var u = r('copy-to'),
+                  d = r('./callback'),
+                  h = r('./utils/deepCopy').deepCopyWith,
+                  m = r('./utils/isBuffer').isBuffer,
+                  y = r('./utils/omit').omit,
+                  e = i;
+                (e.listUploads = (function () {
+                  var r = (0, t.default)(
+                    f.default.mark(function e(t, r) {
+                      var n, s;
+                      return f.default.wrap(
+                        function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                return (
+                                  (n = {}),
+                                  u((r = r || {})).to(n),
+                                  (n.subres = 'uploads'),
+                                  ((n = this._objectRequestParams('GET', '', n)).query = t),
+                                  (n.xmlResponse = !0),
+                                  (n.successStatuses = [200]),
+                                  (e.next = 10),
+                                  this.request(n)
+                                );
+                              case 10:
+                                return (
+                                  (n = e.sent),
+                                  (s = n.data.Upload || []),
+                                  (s = (s = Array.isArray(s) ? s : [s]).map(function (e) {
+                                    return { name: e.Key, uploadId: e.UploadId, initiated: e.Initiated };
+                                  })),
+                                  e.abrupt('return', {
+                                    res: n.res,
+                                    uploads: s,
+                                    bucket: n.data.Bucket,
+                                    nextKeyMarker: n.data.NextKeyMarker,
+                                    nextUploadIdMarker: n.data.NextUploadIdMarker,
+                                    isTruncated: 'true' === n.data.IsTruncated
+                                  })
+                                );
+                              case 15:
+                              case 'end':
+                                return e.stop();
+                            }
+                        },
+                        e,
+                        this
+                      );
+                    })
+                  );
+                  return function (e, t) {
+                    return r.apply(this, arguments);
+                  };
+                })()),
+                  (e.listParts = (function () {
+                    var s = (0, t.default)(
+                      f.default.mark(function e(t, r, n, s) {
+                        var i;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  return (
+                                    (i = {}),
+                                    u((s = s || {})).to(i),
+                                    (i.subres = { uploadId: r }),
+                                    ((i = this._objectRequestParams('GET', t, i)).query = n),
+                                    (i.xmlResponse = !0),
+                                    (i.successStatuses = [200]),
+                                    (e.next = 10),
+                                    this.request(i)
+                                  );
+                                case 10:
+                                  return (
+                                    (i = e.sent),
+                                    e.abrupt('return', {
+                                      res: i.res,
+                                      uploadId: i.data.UploadId,
+                                      bucket: i.data.Bucket,
+                                      name: i.data.Key,
+                                      partNumberMarker: i.data.PartNumberMarker,
+                                      nextPartNumberMarker: i.data.NextPartNumberMarker,
+                                      maxParts: i.data.MaxParts,
+                                      isTruncated: i.data.IsTruncated,
+                                      parts: i.data.Part || []
+                                    })
+                                  );
+                                case 12:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t, r, n) {
+                      return s.apply(this, arguments);
+                    };
+                  })()),
+                  (e.abortMultipartUpload = (function () {
+                    var n = (0, t.default)(
+                      f.default.mark(function e(t, r, n) {
+                        var s;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  return (
+                                    this._stop(),
+                                    (s = {}),
+                                    u((n = n || {})).to(s),
+                                    (s.subres = { uploadId: r }),
+                                    ((s = this._objectRequestParams('DELETE', t, s)).successStatuses = [204]),
+                                    (e.next = 9),
+                                    this.request(s)
+                                  );
+                                case 9:
+                                  return (s = e.sent), e.abrupt('return', { res: s.res });
+                                case 11:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t, r) {
+                      return n.apply(this, arguments);
+                    };
+                  })()),
+                  (e.initMultipartUpload = (function () {
+                    var r = (0, t.default)(
+                      f.default.mark(function e(t, r) {
+                        var n;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  return (
+                                    (n = {}),
+                                    u((r = r || {})).to(n),
+                                    (n.headers = n.headers || {}),
+                                    this._convertMetaToHeaders(r.meta, n.headers),
+                                    (n.subres = 'uploads'),
+                                    ((n = this._objectRequestParams('POST', t, n)).mime = r.mime),
+                                    (n.xmlResponse = !0),
+                                    (n.successStatuses = [200]),
+                                    (e.next = 12),
+                                    this.request(n)
+                                  );
+                                case 12:
+                                  return (
+                                    (n = e.sent),
+                                    e.abrupt('return', {
+                                      res: n.res,
+                                      bucket: n.data.Bucket,
+                                      name: n.data.Key,
+                                      uploadId: n.data.UploadId
+                                    })
+                                  );
+                                case 14:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t) {
+                      return r.apply(this, arguments);
+                    };
+                  })()),
+                  (e.uploadPart = (function () {
+                    var a = (0, t.default)(
+                      f.default.mark(function e(t, r, n, s, i, o, a) {
+                        var c;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  if (((c = { size: o - i }), p && p.browser))
+                                    return (e.next = 5), this._createBuffer(s, i, o);
+                                  e.next = 8;
+                                  break;
+                                case 5:
+                                  (c.content = e.sent), (e.next = 11);
+                                  break;
+                                case 8:
+                                  return (e.next = 10), this._createStream(s, i, o);
+                                case 10:
+                                  c.stream = e.sent;
+                                case 11:
+                                  return (e.next = 13), this._uploadPart(t, r, n, c, a);
+                                case 13:
+                                  return e.abrupt('return', e.sent);
+                                case 14:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t, r, n, s, i, o) {
+                      return a.apply(this, arguments);
+                    };
+                  })()),
+                  (e.completeMultipartUpload = (function () {
+                    var s = (0, t.default)(
+                      f.default.mark(function e(t, r, n, s) {
+                        var i, o, a, c, l, u, p;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  for (
+                                    i = n
+                                      .concat()
+                                      .sort(function (e, t) {
+                                        return e.number - t.number;
+                                      })
+                                      .filter(function (e, t, r) {
+                                        return !t || e.number !== r[t - 1].number;
+                                      }),
+                                      o = '<?xml version="1.0" encoding="UTF-8"?>\n<CompleteMultipartUpload>\n',
+                                      a = 0;
+                                    a < i.length;
+                                    a++
+                                  )
+                                    (c = i[a]),
+                                      (o =
+                                        (o = (o += '<Part>\n') + '<PartNumber>'.concat(c.number, '</PartNumber>\n')) +
+                                        '<ETag>'.concat(c.etag, '</ETag>\n') +
+                                        '</Part>\n');
+                                  return (
+                                    (o += '</CompleteMultipartUpload>'),
+                                    (p = {}),
+                                    ((p = h((s = s || {}), function (e) {
+                                      if (m(e)) return null;
+                                    })).subres = { uploadId: r }),
+                                    (p.headers = y(p.headers, ['x-oss-server-side-encryption', 'x-oss-storage-class'])),
+                                    (l = this._objectRequestParams('POST', t, p)),
+                                    d.encodeCallback(l, p),
+                                    (l.mime = 'xml'),
+                                    (l.content = o),
+                                    (l.headers && l.headers['x-oss-callback']) || (l.xmlResponse = !0),
+                                    (l.successStatuses = [200]),
+                                    (e.next = 17),
+                                    this.request(l)
+                                  );
+                                case 17:
+                                  if (((u = e.sent), s.progress)) return (e.next = 21), s.progress(1, null, u.res);
+                                  e.next = 21;
+                                  break;
+                                case 21:
+                                  return (
+                                    (p = { res: u.res, bucket: l.bucket, name: t, etag: u.res.headers.etag }),
+                                    l.headers &&
+                                      l.headers['x-oss-callback'] &&
+                                      (p.data = JSON.parse(u.data.toString())),
+                                    e.abrupt('return', p)
+                                  );
+                                case 24:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t, r, n) {
+                      return s.apply(this, arguments);
+                    };
+                  })()),
+                  (e._uploadPart = (function () {
+                    var i = (0, t.default)(
+                      f.default.mark(function e(t, r, n, s, i) {
+                        var o, a, c;
+                        return f.default.wrap(
+                          function (e) {
+                            for (;;)
+                              switch ((e.prev = e.next)) {
+                                case 0:
+                                  return (
+                                    (o = {}),
+                                    u((i = i || {})).to(o),
+                                    (o.headers = o.headers || {}),
+                                    (o.headers = l(l({}, o.headers), {}, { 'Content-Length': s.size })),
+                                    (o.headers = y(o.headers, ['x-oss-server-side-encryption'])),
+                                    (o.subres = { partNumber: n, uploadId: r }),
+                                    ((a = this._objectRequestParams('PUT', t, o)).mime = o.mime),
+                                    p && p.browser ? (a.content = s.content) : (a.stream = s.stream),
+                                    (a.successStatuses = [200]),
+                                    (a.disabledMD5 = i.disabledMD5),
+                                    (e.next = 15),
+                                    this.request(a)
+                                  );
+                                case 15:
+                                  if ((c = e.sent).res.headers.etag) {
+                                    e.next = 18;
+                                    break;
+                                  }
+                                  throw new Error(
+                                    'Please set the etag of expose-headers in OSS \n https://help.aliyun.com/document_detail/32069.html'
+                                  );
+                                case 18:
+                                  return (
+                                    s.stream && ((s.stream = null), (a.stream = null)),
+                                    e.abrupt('return', { name: t, etag: c.res.headers.etag, res: c.res })
+                                  );
+                                case 20:
+                                case 'end':
+                                  return e.stop();
+                              }
+                          },
+                          e,
+                          this
+                        );
+                      })
+                    );
+                    return function (e, t, r, n, s) {
+                      return i.apply(this, arguments);
+                    };
+                  })());
+              }.call(this);
+            }.call(this, r('_process'));
+          },
+          {
+            './callback': 24,
+            './utils/deepCopy': 57,
+            './utils/isBuffer': 64,
+            './utils/omit': 71,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/defineProperty': 76,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            _process: 441,
+            'copy-to': 91,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.filter.js': 271,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.array.sort.js': 279,
+            'core-js/modules/es.object.get-own-property-descriptor.js': 286,
+            'core-js/modules/es.object.get-own-property-descriptors.js': 287,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.symbol.js': 312,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        31: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              c = n(e('@babel/runtime/regenerator')),
+              s = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              l = e('url'),
+              u = e('utility'),
+              p = e('copy-to'),
+              f = e('../../common/signUtils'),
+              d = e('../utils/isIP').isIP,
+              h = e('../utils/setSTSToken').setSTSToken,
+              m = e('../utils/isFunction').isFunction;
+            r.asyncSignatureUrl = (function () {
+              var r = (0, s.default)(
+                c.default.mark(function e(t, r) {
+                  var n, s, i, o, a;
+                  return c.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if (d(this.options.endpoint.hostname))
+                              throw new Error('can not get the object URL when endpoint is IP');
+                            e.next = 2;
+                            break;
+                          case 2:
+                            if (
+                              ((r = r || {}),
+                              (t = this._objectName(t)),
+                              (r.method = r.method || 'GET'),
+                              (n = u.timestamp() + (r.expires || 1800)),
+                              (s = { bucket: this.options.bucket, object: t }),
+                              (i = this._getResource(s)),
+                              this.options.stsToken && m(this.options.refreshSTSToken))
+                            )
+                              return (e.next = 11), h.call(this);
+                            e.next = 11;
+                            break;
+                          case 11:
+                            return (
+                              this.options.stsToken && (r['security-token'] = this.options.stsToken),
+                              (o = f._signatureForURL(this.options.accessKeySecret, r, i, n)),
+                              ((a = l.parse(this._getReqUrl(s))).query = {
+                                OSSAccessKeyId: this.options.accessKeyId,
+                                Expires: n,
+                                Signature: o.Signature
+                              }),
+                              p(o.subResource).to(a.query),
+                              e.abrupt('return', a.format())
+                            );
+                          case 17:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../../common/signUtils': 50,
+            '../utils/isFunction': 66,
+            '../utils/isIP': 67,
+            '../utils/setSTSToken': 74,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'copy-to': 91,
+            url: 446,
+            utility: 448
+          }
+        ],
+        32: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              c =
+                (e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.array.find.js'),
+                e('core-js/modules/es.array.includes.js'),
+                e('core-js/modules/es.array.concat.js'),
+                e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.string.replace.js'),
+                n(e('@babel/runtime/helpers/typeof'))),
+              i = n(e('@babel/runtime/helpers/asyncToGenerator')),
+              s = e('../utils/checkBucketName').checkBucketName,
+              n = r,
+              l = [
+                'content-type',
+                'content-encoding',
+                'content-language',
+                'content-disposition',
+                'cache-control',
+                'expires'
+              ];
+            (n.copy = (function () {
+              var s = (0, i.default)(
+                a.default.mark(function e(t, r, n, s) {
+                  var i, o;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((s = (s = 'object' === (0, c.default)(n) ? n : s) || {}).headers = s.headers || {}),
+                              Object.keys(s.headers).forEach(function (e) {
+                                s.headers['x-oss-copy-source-'.concat(e.toLowerCase())] = s.headers[e];
+                              }),
+                              (s.meta ||
+                                Object.keys(s.headers).find(function (e) {
+                                  return l.includes(e.toLowerCase());
+                                })) &&
+                                (s.headers['x-oss-metadata-directive'] = 'REPLACE'),
+                              this._convertMetaToHeaders(s.meta, s.headers),
+                              (r = this._getSourceName(r, n)),
+                              s.versionId && (r = ''.concat(r, '?versionId=').concat(s.versionId)),
+                              (s.headers['x-oss-copy-source'] = r),
+                              ((i = this._objectRequestParams('PUT', t, s)).xmlResponse = !0),
+                              (i.successStatuses = [200, 304]),
+                              (e.next = 14),
+                              this.request(i)
+                            );
+                          case 14:
+                            return (
+                              (i = e.sent),
+                              (o = (o = i.data) && { etag: o.ETag, lastModified: o.LastModified }),
+                              e.abrupt('return', { data: o, res: i.res })
+                            );
+                          case 18:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r, n) {
+                return s.apply(this, arguments);
+              };
+            })()),
+              (n._getSourceName = function (e, t) {
+                return (
+                  'string' == typeof t
+                    ? (e = this._objectName(e))
+                    : '/' !== e[0]
+                    ? (t = this.options.bucket)
+                    : ((t = e.replace(/\/(.+?)(\/.*)/, '$1')), (e = e.replace(/(\/.+?\/)(.*)/, '$2'))),
+                  s(t),
+                  (e = encodeURIComponent(e)),
+                  (e = '/'.concat(t, '/').concat(e))
+                );
+              });
+          },
+          {
+            '../utils/checkBucketName': 51,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.find.js': 272,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        33: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.delete = (function () {
+              var t = (0, i.default)(
+                s.default.mark(function e(t) {
+                  var r,
+                    n = arguments;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((r = 1 < n.length && void 0 !== n[1] ? n[1] : {}).subres = Object.assign({}, r.subres)),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              ((r = this._objectRequestParams('DELETE', t, r)).successStatuses = [204]),
+                              (e.next = 7),
+                              this.request(r)
+                            );
+                          case 7:
+                            return (r = e.sent), e.abrupt('return', { res: r.res });
+                          case 9:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        34: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              f = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              d = e('utility'),
+              h = e('../utils/obj2xml').obj2xml;
+            r.deleteMulti = (function () {
+              var t = (0, s.default)(
+                f.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c,
+                    l,
+                    u,
+                    p = arguments;
+                  return f.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if (((r = 1 < p.length && void 0 !== p[1] ? p[1] : {}), (n = []), t && t.length)) {
+                              e.next = 4;
+                              break;
+                            }
+                            throw new Error('names is required');
+                          case 4:
+                            for (s = 0; s < t.length; s++)
+                              (i = {}),
+                                'string' == typeof t[s]
+                                  ? (i.Key = d.escape(this._objectName(t[s])))
+                                  : ((a = t[s]),
+                                    (o = a.key),
+                                    (a = a.versionId),
+                                    (i.Key = d.escape(this._objectName(o))),
+                                    (i.VersionId = a)),
+                                n.push(i);
+                            return (
+                              (c = { Delete: { Quiet: !!r.quiet, Object: n } }),
+                              (c = h(c, { headers: !0 })),
+                              (r.subres = Object.assign({ delete: '' }, r.subres)),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              ((l = this._objectRequestParams('POST', '', r)).mime = 'xml'),
+                              (l.content = c),
+                              (l.xmlResponse = !0),
+                              (l.successStatuses = [200]),
+                              (e.next = 16),
+                              this.request(l)
+                            );
+                          case 16:
+                            return (
+                              (c = e.sent),
+                              (l = c.data),
+                              (u = (l && l.Deleted) || null) && !Array.isArray(u) && (u = [u]),
+                              e.abrupt('return', { res: c.res, deleted: u || [] })
+                            );
+                          case 21:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284,
+            utility: 448
+          }
+        ],
+        35: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.deleteObjectTagging = (function () {
+              var t = (0, i.default)(
+                s.default.mark(function e(t) {
+                  var r,
+                    n = arguments;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((r = 1 < n.length && void 0 !== n[1] ? n[1] : {}).subres = Object.assign(
+                                { tagging: '' },
+                                r.subres
+                              )),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              (t = this._objectName(t)),
+                              ((r = this._objectRequestParams('DELETE', t, r)).successStatuses = [204]),
+                              (e.next = 8),
+                              this.request(r)
+                            );
+                          case 8:
+                            return (r = e.sent), e.abrupt('return', { status: r.status, res: r.res });
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        36: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.concat.js');
+            var s = e('url'),
+              i = e('../utils/isIP').isIP;
+            r.generateObjectUrl = function (e, t) {
+              if (i(this.options.endpoint.hostname)) throw new Error('can not get the object URL when endpoint is IP');
+              var r, n;
+              return (
+                t
+                  ? '/' !== t[t.length - 1] && (t += '/')
+                  : ((t = this.options.endpoint.format()),
+                    (r = s.parse(t)),
+                    (n = this.options.bucket),
+                    (r.hostname = ''.concat(n, '.').concat(r.hostname)),
+                    (r.host = ''.concat(n, '.').concat(r.host)),
+                    (t = r.format())),
+                t + this._escape(this._objectName(e))
+              );
+            };
+          },
+          { '../utils/isIP': 67, 'core-js/modules/es.array.concat.js': 269, url: 446 }
+        ],
+        37: [
+          function (r, e, n) {
+            !function (d) {
+              !function () {
+                'use strict';
+                var e = r('@babel/runtime/helpers/interopRequireDefault'),
+                  u = e(r('@babel/runtime/regenerator')),
+                  t = (r('core-js/modules/es.object.assign.js'), e(r('@babel/runtime/helpers/asyncToGenerator'))),
+                  p = r('fs'),
+                  f = r('is-type-of');
+                n.get = (function () {
+                  var r = (0, t.default)(
+                    u.default.mark(function e(t, r) {
+                      var n,
+                        s,
+                        i,
+                        o,
+                        a,
+                        c,
+                        l = arguments;
+                      return u.default.wrap(
+                        function (e) {
+                          for (;;)
+                            switch ((e.prev = e.next)) {
+                              case 0:
+                                return (
+                                  (n = 2 < l.length && void 0 !== l[2] ? l[2] : {}),
+                                  (s = null),
+                                  (i = !1),
+                                  f.writableStream(r)
+                                    ? (s = r)
+                                    : f.string(r)
+                                    ? ((s = p.createWriteStream(r)), (i = !0))
+                                    : (n = r),
+                                  (n = n || {}),
+                                  (o = d && d.browser),
+                                  (c = null === n.responseCacheControl ? '' : 'no-cache'),
+                                  (o = o && c ? { 'response-cache-control': c } : {}),
+                                  (n.subres = Object.assign(o, n.subres)),
+                                  n.versionId && (n.subres.versionId = n.versionId),
+                                  n.process && (n.subres['x-oss-process'] = n.process),
+                                  (e.prev = 11),
+                                  ((c = this._objectRequestParams('GET', t, n)).writeStream = s),
+                                  (c.successStatuses = [200, 206, 304]),
+                                  (e.next = 17),
+                                  this.request(c)
+                                );
+                              case 17:
+                                (a = e.sent), i && s.destroy(), (e.next = 28);
+                                break;
+                              case 21:
+                                if (((e.prev = 21), (e.t0 = e.catch(11)), i))
+                                  return s.destroy(), (e.next = 27), this._deleteFileSafe(r);
+                                e.next = 27;
+                                break;
+                              case 27:
+                                throw e.t0;
+                              case 28:
+                                return e.abrupt('return', { res: a.res, content: a.data });
+                              case 29:
+                              case 'end':
+                                return e.stop();
+                            }
+                        },
+                        e,
+                        this,
+                        [[11, 21]]
+                      );
+                    })
+                  );
+                  return function (e, t) {
+                    return r.apply(this, arguments);
+                  };
+                })();
+              }.call(this);
+            }.call(this, r('_process'));
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            _process: 441,
+            'core-js/modules/es.object.assign.js': 284,
+            fs: 87,
+            'is-type-of': 440
+          }
+        ],
+        38: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.getACL = (function () {
+              var t = (0, i.default)(
+                s.default.mark(function e(t) {
+                  var r,
+                    n = arguments;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((r = 1 < n.length && void 0 !== n[1] ? n[1] : {}).subres = Object.assign(
+                                { acl: '' },
+                                r.subres
+                              )),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              (t = this._objectName(t)),
+                              ((r = this._objectRequestParams('GET', t, r)).successStatuses = [200]),
+                              (r.xmlResponse = !0),
+                              (e.next = 9),
+                              this.request(r)
+                            );
+                          case 9:
+                            return (
+                              (r = e.sent),
+                              e.abrupt('return', {
+                                acl: r.data.AccessControlList.Grant,
+                                owner: { id: r.data.Owner.ID, displayName: r.data.Owner.DisplayName },
+                                res: r.res
+                              })
+                            );
+                          case 11:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        39: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              l = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.string.replace.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.array.map.js'),
+                e('core-js/modules/es.number.constructor.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              n = r,
+              u = e('../utils/isObject').isObject,
+              p = e('../utils/isArray').isArray;
+            function i() {
+              return o.apply(this, arguments);
+            }
+            function o() {
+              return (o = (0, s.default)(
+                l.default.mark(function e() {
+                  var t,
+                    r,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c = arguments;
+                  return l.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if (
+                              ((t = 0 < c.length && void 0 !== c[0] ? c[0] : {}),
+                              (r = 1 < c.length && void 0 !== c[1] ? c[1] : {}),
+                              t.versionIdMarker && void 0 === t.keyMarker)
+                            )
+                              throw new Error('A version-id marker cannot be specified without a key marker');
+                            e.next = 4;
+                            break;
+                          case 4:
+                            return (
+                              (r.subres = Object.assign({ versions: '' }, r.subres)),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              ((n = this._objectRequestParams('GET', '', r)).xmlResponse = !0),
+                              (n.successStatuses = [200]),
+                              (n.query = (function () {
+                                var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {},
+                                  r = {};
+                                u(t) &&
+                                  Object.keys(t).forEach(function (e) {
+                                    r[e.replace(/([A-Z])/g, '-$1').toLowerCase()] = t[e];
+                                  });
+                                return r;
+                              })(t)),
+                              (e.next = 12),
+                              this.request(n)
+                            );
+                          case 12:
+                            return (
+                              (n = e.sent),
+                              (s = n.data.Version || []),
+                              (i = n.data.DeleteMarker || []),
+                              (o = this),
+                              (s =
+                                s &&
+                                (s = Array.isArray(s) ? s : [s]).map(function (e) {
+                                  return {
+                                    name: e.Key,
+                                    url: o._objectUrl(e.Key),
+                                    lastModified: e.LastModified,
+                                    isLatest: 'true' === e.IsLatest,
+                                    versionId: e.VersionId,
+                                    etag: e.ETag,
+                                    type: e.Type,
+                                    size: Number(e.Size),
+                                    storageClass: e.StorageClass,
+                                    owner: { id: e.Owner.ID, displayName: e.Owner.DisplayName }
+                                  };
+                                })),
+                              (i =
+                                i &&
+                                (i = p(i) ? i : [i]).map(function (e) {
+                                  return {
+                                    name: e.Key,
+                                    lastModified: e.LastModified,
+                                    versionId: e.VersionId,
+                                    owner: { id: e.Owner.ID, displayName: e.Owner.DisplayName }
+                                  };
+                                })),
+                              (a =
+                                (a = n.data.CommonPrefixes || null) &&
+                                (a = p(a) ? a : [a]).map(function (e) {
+                                  return e.Prefix;
+                                })),
+                              e.abrupt('return', {
+                                res: n.res,
+                                objects: s,
+                                deleteMarker: i,
+                                prefixes: a,
+                                nextMarker: n.data.NextKeyMarker || null,
+                                NextVersionIdMarker: n.data.NextVersionIdMarker || null,
+                                nextKeyMarker: n.data.NextKeyMarker || null,
+                                nextVersionIdMarker: n.data.NextVersionIdMarker || null,
+                                isTruncated: 'true' === n.data.IsTruncated
+                              })
+                            );
+                          case 21:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            (n.getBucketVersions = i), (n.listObjectVersions = i);
+          },
+          {
+            '../utils/isArray': 62,
+            '../utils/isObject': 68,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.number.constructor.js': 283,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        40: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.getObjectMeta = (function () {
+              var r = (0, i.default)(
+                s.default.mark(function e(t, r) {
+                  var n;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (r = r || {}),
+                              (t = this._objectName(t)),
+                              (r.subres = Object.assign({ objectMeta: '' }, r.subres)),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              ((n = this._objectRequestParams('HEAD', t, r)).successStatuses = [200]),
+                              (e.next = 8),
+                              this.request(n)
+                            );
+                          case 8:
+                            return (n = e.sent), e.abrupt('return', { status: n.status, res: n.res });
+                          case 10:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        41: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              a = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              n = r,
+              c = e('../utils/isObject').isObject;
+            n.getObjectTagging = (function () {
+              var t = (0, s.default)(
+                a.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s,
+                    i,
+                    o = arguments;
+                  return a.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((n = 1 < o.length && void 0 !== o[1] ? o[1] : {}).subres = Object.assign(
+                                { tagging: '' },
+                                n.subres
+                              )),
+                              n.versionId && (n.subres.versionId = n.versionId),
+                              (t = this._objectName(t)),
+                              ((n = this._objectRequestParams('GET', t, n)).successStatuses = [200]),
+                              (e.next = 8),
+                              this.request(n)
+                            );
+                          case 8:
+                            return (r = e.sent), (e.next = 11), this.parseXML(r.data);
+                          case 11:
+                            return (
+                              (n = e.sent),
+                              (s = (s = n.TagSet.Tag) && c(s) ? [s] : s || []),
+                              (i = {}),
+                              s.forEach(function (e) {
+                                i[e.Key] = e.Value;
+                              }),
+                              e.abrupt('return', { status: r.status, res: r.res, tag: i })
+                            );
+                          case 17:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/isObject': 68,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        42: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../utils/isIP').isIP;
+            r.getObjectUrl = function (e, t) {
+              if (n(this.options.endpoint.hostname)) throw new Error('can not get the object URL when endpoint is IP');
+              return (
+                t ? '/' !== t[t.length - 1] && (t += '/') : (t = this.options.endpoint.format()),
+                t + this._escape(this._objectName(e))
+              );
+            };
+          },
+          { '../utils/isIP': 67 }
+        ],
+        43: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.getSymlink = (function () {
+              var t = (0, s.default)(
+                i.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s = arguments;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((r = 1 < s.length && void 0 !== s[1] ? s[1] : {}).subres = Object.assign(
+                                { symlink: '' },
+                                r.subres
+                              )),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              (t = this._objectName(t)),
+                              ((r = this._objectRequestParams('GET', t, r)).successStatuses = [200]),
+                              (e.next = 8),
+                              this.request(r)
+                            );
+                          case 8:
+                            return (
+                              (r = e.sent),
+                              (n = r.res.headers['x-oss-symlink-target']),
+                              e.abrupt('return', { targetName: decodeURIComponent(n), res: r.res })
+                            );
+                          case 11:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        44: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.head = (function () {
+              var t = (0, s.default)(
+                o.default.mark(function e(t) {
+                  var r,
+                    n,
+                    s,
+                    i = arguments;
+                  return o.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((r = 1 < i.length && void 0 !== i[1] ? i[1] : {}).subres = Object.assign({}, r.subres)),
+                              r.versionId && (r.subres.versionId = r.versionId),
+                              ((r = this._objectRequestParams('HEAD', t, r)).successStatuses = [200, 304]),
+                              (e.next = 7),
+                              this.request(r)
+                            );
+                          case 7:
+                            return (
+                              (n = e.sent),
+                              (s = { meta: null, res: n.res, status: n.status }),
+                              200 === n.status &&
+                                Object.keys(n.headers).forEach(function (e) {
+                                  0 === e.indexOf('x-oss-meta-') &&
+                                    (s.meta || (s.meta = {}), (s.meta[e.substring(11)] = n.headers[e]));
+                                }),
+                              e.abrupt('return', s)
+                            );
+                          case 11:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e) {
+                return t.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        45: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.putACL = (function () {
+              var n = (0, s.default)(
+                i.default.mark(function e(t, r, n) {
+                  var s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((n = n || {}).subres = Object.assign({ acl: '' }, n.subres)),
+                              n.versionId && (n.subres.versionId = n.versionId),
+                              (n.headers = n.headers || {}),
+                              (n.headers['x-oss-object-acl'] = r),
+                              (t = this._objectName(t)),
+                              ((s = this._objectRequestParams('PUT', t, n)).successStatuses = [200]),
+                              (e.next = 10),
+                              this.request(s)
+                            );
+                          case 10:
+                            return (s = e.sent), e.abrupt('return', { res: s.res });
+                          case 12:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r) {
+                return n.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        46: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o = n(e('@babel/runtime/regenerator')),
+              s =
+                (e('core-js/modules/es.object.assign.js'),
+                e('core-js/modules/es.array.map.js'),
+                e('core-js/modules/es.object.keys.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              a = e('../utils/obj2xml').obj2xml,
+              c = e('../utils/checkObjectTag').checkObjectTag;
+            r.putObjectTagging = (function () {
+              var r = (0, s.default)(
+                o.default.mark(function e(t, r) {
+                  var n,
+                    s,
+                    i = arguments;
+                  return o.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              (n = 2 < i.length && void 0 !== i[2] ? i[2] : {}),
+                              c(r),
+                              (n.subres = Object.assign({ tagging: '' }, n.subres)),
+                              n.versionId && (n.subres.versionId = n.versionId),
+                              (t = this._objectName(t)),
+                              ((n = this._objectRequestParams('PUT', t, n)).successStatuses = [200]),
+                              (r = Object.keys(r).map(function (e) {
+                                return { Key: e, Value: r[e] };
+                              })),
+                              (s = { Tagging: { TagSet: { Tag: r } } }),
+                              (n.mime = 'xml'),
+                              (n.content = a(s)),
+                              (e.next = 13),
+                              this.request(n)
+                            );
+                          case 13:
+                            return (s = e.sent), e.abrupt('return', { res: s.res, status: s.status });
+                          case 15:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t) {
+                return r.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '../utils/checkObjectTag': 53,
+            '../utils/obj2xml': 70,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.keys.js': 289
+          }
+        ],
+        47: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              i = n(e('@babel/runtime/regenerator')),
+              s = (e('core-js/modules/es.object.assign.js'), n(e('@babel/runtime/helpers/asyncToGenerator')));
+            r.putSymlink = (function () {
+              var n = (0, s.default)(
+                i.default.mark(function e(t, r, n) {
+                  var s;
+                  return i.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            return (
+                              ((n = n || {}).headers = n.headers || {}),
+                              (r = this._escape(this._objectName(r))),
+                              this._convertMetaToHeaders(n.meta, n.headers),
+                              (n.headers['x-oss-symlink-target'] = r),
+                              (n.subres = Object.assign({ symlink: '' }, n.subres)),
+                              n.versionId && (n.subres.versionId = n.versionId),
+                              n.storageClass && (n.headers['x-oss-storage-class'] = n.storageClass),
+                              (t = this._objectName(t)),
+                              ((s = this._objectRequestParams('PUT', t, n)).successStatuses = [200]),
+                              (e.next = 13),
+                              this.request(s)
+                            );
+                          case 13:
+                            return (s = e.sent), e.abrupt('return', { res: s.res });
+                          case 15:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              );
+              return function (e, t, r) {
+                return n.apply(this, arguments);
+              };
+            })();
+          },
+          {
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.object.assign.js': 284
+          }
+        ],
+        48: [
+          function (e, t, r) {
+            'use strict';
+            var s = e('url'),
+              i = e('utility'),
+              o = e('copy-to'),
+              a = e('../../common/signUtils'),
+              c = e('../utils/isIP').isIP;
+            r.signatureUrl = function (e, t) {
+              if (c(this.options.endpoint.hostname)) throw new Error('can not get the object URL when endpoint is IP');
+              (t = t || {}), (e = this._objectName(e)), (t.method = t.method || 'GET');
+              var r = i.timestamp() + (t.expires || 1800),
+                e = { bucket: this.options.bucket, object: e },
+                n = this._getResource(e),
+                t =
+                  (this.options.stsToken && (t['security-token'] = this.options.stsToken),
+                  a._signatureForURL(this.options.accessKeySecret, t, n, r)),
+                n = s.parse(this._getReqUrl(e));
+              return (
+                (n.query = { OSSAccessKeyId: this.options.accessKeyId, Expires: r, Signature: t.Signature }),
+                o(t.subResource).to(n.query),
+                n.format()
+              );
+            };
+          },
+          { '../../common/signUtils': 50, '../utils/isIP': 67, 'copy-to': 91, url: 446, utility: 448 }
+        ],
+        49: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              p = n(e('@babel/runtime/regenerator')),
+              i =
+                (e('core-js/modules/es.array.iterator.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/es.promise.js'),
+                e('core-js/modules/es.string.iterator.js'),
+                e('core-js/modules/web.dom-collections.iterator.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.function.name.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              s = e('./utils/isArray').isArray,
+              n = r;
+            (n._parallelNode = (function () {
+              var s = (0, i.default)(
+                p.default.mark(function e(t, r, n, s) {
+                  var i, o, a, c, l, u;
+                  return p.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            (i = this),
+                              (o = []),
+                              (a = []),
+                              (c = t.length / r),
+                              (l = t.length % r),
+                              (c = 0 == l ? c : (t.length - l) / r + 1),
+                              (l = 1),
+                              (u = 0);
+                          case 8:
+                            if (!(u < t.length)) {
+                              e.next = 26;
+                              break;
+                            }
+                            if (i.isCancel()) return e.abrupt('break', 26);
+                            e.next = 11;
+                            break;
+                          case 11:
+                            if (
+                              (s ? a.push(n(i, t[u], s)) : a.push(n(i, t[u])),
+                              a.length === r || (l === c && u === t.length - 1))
+                            )
+                              return (e.prev = 13), (l += 1), (e.next = 17), Promise.all(a);
+                            e.next = 23;
+                            break;
+                          case 17:
+                            e.next = 22;
+                            break;
+                          case 19:
+                            (e.prev = 19), (e.t0 = e.catch(13)), o.push(e.t0);
+                          case 22:
+                            a = [];
+                          case 23:
+                            u++, (e.next = 8);
+                            break;
+                          case 26:
+                            return e.abrupt('return', o);
+                          case 27:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this,
+                    [[13, 19]]
+                  );
+                })
+              );
+              return function (e, t, r, n) {
+                return s.apply(this, arguments);
+              };
+            })()),
+              (n._parallel = function (p, f, d) {
+                var h = this;
+                return new Promise(function (t) {
+                  var r,
+                    e,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c = [];
+                  function l(e) {
+                    --o,
+                      e
+                        ? ((i = !0), c.push(e), t(c))
+                        : i && o <= 0
+                        ? ((i = !0), t(c))
+                        : a || (h.isCancel() ? t(c) : u());
+                  }
+                  function u() {
+                    for (a = !0; o < f && !i && !h.isCancel(); ) {
+                      var e = r();
+                      if (null === e || 0 < c.length) return (i = !0), void (o <= 0 && t(c));
+                      (o += 1),
+                        !(function (e, t) {
+                          d(e)
+                            .then(function (e) {
+                              t(null, e);
+                            })
+                            .catch(function (e) {
+                              t(e);
+                            });
+                        })(
+                          e.value,
+                          (function (s) {
+                            return function () {
+                              if (null === s) throw new Error('Callback was already called.');
+                              var e = s;
+                              s = null;
+                              for (var t = arguments.length, r = new Array(t), n = 0; n < t; n++) r[n] = arguments[n];
+                              e.apply(this, r);
+                            };
+                          })(l)
+                        );
+                    }
+                    a = !1;
+                  }
+                  f <= 0 || !p
+                    ? t(c)
+                    : ((n = -1),
+                      (s = (e = p).length),
+                      (o = 0),
+                      (a = i =
+                        !(r = function () {
+                          return ++n < s && !h.isCancel() ? { value: e[n], key: n } : null;
+                        })),
+                      u());
+                });
+              }),
+              (n.cancel = function (e) {
+                (this.options.cancelFlag = !0),
+                  s(this.multipartUploadStreams) &&
+                    this.multipartUploadStreams.forEach(function (e) {
+                      !1 === e.destroyed && e.destroy({ name: 'cancel', message: 'cancel' });
+                    }),
+                  (this.multipartUploadStreams = []),
+                  e && this.abortMultipartUpload(e.name, e.uploadId, e.options);
+              }),
+              (n.isCancel = function () {
+                return this.options.cancelFlag;
+              }),
+              (n.resetCancelFlag = function () {
+                this.options.cancelFlag = !1;
+              }),
+              (n._stop = function () {
+                this.options.cancelFlag = !0;
+              }),
+              (n._makeCancelEvent = function () {
+                return { status: 0, name: 'cancel' };
+              }),
+              (n._makeAbortEvent = function () {
+                return { status: 0, name: 'abort', message: 'upload task has been abort' };
+              });
+          },
+          {
+            './utils/isArray': 62,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.iterator.js': 275,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.string.iterator.js': 302,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            'core-js/modules/web.dom-collections.iterator.js': 339
+          }
+        ],
+        50: [
+          function (e, t, r) {
+            !function (l) {
+              !function () {
+                'use strict';
+                e('core-js/modules/es.string.trim.js'),
+                  e('core-js/modules/es.array.sort.js'),
+                  e('core-js/modules/es.array.join.js'),
+                  e('core-js/modules/es.object.to-string.js'),
+                  e('core-js/modules/web.dom-collections.for-each.js'),
+                  e('core-js/modules/es.object.keys.js'),
+                  e('core-js/modules/es.array.concat.js'),
+                  e('core-js/modules/es.regexp.to-string.js');
+                var n = e('./../../shims/crypto/crypto.js'),
+                  s = e('is-type-of'),
+                  a = e('./utils/lowercaseKeyHeader').lowercaseKeyHeader;
+                (r.buildCanonicalizedResource = function (e, t) {
+                  var r = ''.concat(e),
+                    n = '?';
+                  return (
+                    s.string(t) && '' !== t.trim()
+                      ? (r += n + t)
+                      : s.array(t)
+                      ? (t.sort(), (r += n + t.join('&')))
+                      : t &&
+                        Object.keys(t)
+                          .sort(function (e, t) {
+                            return e[0] > t[0] ? 1 : e[0] < t[0] ? -1 : 0;
+                          })
+                          .forEach(function (e) {
+                            (r += n + e), (!t[e] && 0 !== t[e]) || (r += '='.concat(t[e])), (n = '&');
+                          }),
+                    r
+                  );
+                }),
+                  (r.buildCanonicalString = function (e, t, r, n) {
+                    var s = a((r = r || {}).headers),
+                      i = [],
+                      o = {},
+                      e = [e.toUpperCase(), s['content-md5'] || '', s['content-type'], n || s['x-oss-date']];
+                    return (
+                      Object.keys(s).forEach(function (e) {
+                        var t = e.toLowerCase();
+                        0 === t.indexOf('x-oss-') && (o[t] = String(s[e]).trim());
+                      }),
+                      Object.keys(o)
+                        .sort()
+                        .forEach(function (e) {
+                          i.push(''.concat(e, ':').concat(o[e]));
+                        }),
+                      (e = e.concat(i)).push(this.buildCanonicalizedResource(t, r.parameters)),
+                      e.join('\n')
+                    );
+                  }),
+                  (r.computeSignature = function (e, t) {
+                    var r = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : 'utf-8';
+                    return n.createHmac('sha1', e).update(l.from(t, r)).digest('base64');
+                  }),
+                  (r.authorization = function (e, t, r, n) {
+                    return 'OSS '.concat(e, ':').concat(this.computeSignature(t, r, n));
+                  }),
+                  (r._signatureForURL = function (e) {
+                    var t,
+                      n = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {},
+                      r = 2 < arguments.length ? arguments[2] : void 0,
+                      s = 3 < arguments.length ? arguments[3] : void 0,
+                      i = 4 < arguments.length ? arguments[4] : void 0,
+                      o = {},
+                      a = n.subResource,
+                      c = void 0 === a ? {} : a,
+                      a =
+                        (n.process && (c['x-oss-process'] = n.process),
+                        n.trafficLimit && (c['x-oss-traffic-limit'] = n.trafficLimit),
+                        n.response &&
+                          Object.keys(n.response).forEach(function (e) {
+                            var t = 'response-'.concat(e.toLowerCase());
+                            c[t] = n.response[e];
+                          }),
+                        Object.keys(n).forEach(function (e) {
+                          var t = e.toLowerCase(),
+                            r = n[e];
+                          0 === t.indexOf('x-oss-')
+                            ? (o[t] = r)
+                            : (0 !== t.indexOf('content-md5') && 0 !== t.indexOf('content-type')) || (o[e] = r);
+                        }),
+                        Object.prototype.hasOwnProperty.call(n, 'security-token') &&
+                          (c['security-token'] = n['security-token']),
+                        Object.prototype.hasOwnProperty.call(n, 'callback') &&
+                          ((a = { callbackUrl: encodeURI(n.callback.url), callbackBody: n.callback.body }),
+                          n.callback.host && (a.callbackHost = n.callback.host),
+                          n.callback.contentType && (a.callbackBodyType = n.callback.contentType),
+                          (c.callback = l.from(JSON.stringify(a)).toString('base64')),
+                          n.callback.customValue &&
+                            ((t = {}),
+                            Object.keys(n.callback.customValue).forEach(function (e) {
+                              t['x:'.concat(e)] = n.callback.customValue[e];
+                            }),
+                            (c['callback-var'] = l.from(JSON.stringify(t)).toString('base64')))),
+                        this.buildCanonicalString(n.method, r, { headers: o, parameters: c }, s.toString()));
+                    return { Signature: this.computeSignature(e, a, i), subResource: c };
+                  });
+              }.call(this);
+            }.call(this, e('buffer').Buffer);
+          },
+          {
+            './../../shims/crypto/crypto.js': 435,
+            './utils/lowercaseKeyHeader': 69,
+            buffer: 89,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.join.js': 276,
+            'core-js/modules/es.array.sort.js': 279,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.trim.js': 307,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            'is-type-of': 440
+          }
+        ],
+        51: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.regexp.exec.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.checkBucketName = void 0),
+              (r.checkBucketName = function (e) {
+                if (
+                  !(
+                    1 < arguments.length && void 0 !== arguments[1] && arguments[1]
+                      ? /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/
+                      : /^[a-z0-9_][a-z0-9-_]{1,61}[a-z0-9_]$/
+                  ).test(e)
+                )
+                  throw new Error('The bucket must be conform to the specifications');
+              });
+          },
+          { 'core-js/modules/es.regexp.exec.js': 299 }
+        ],
+        52: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.regexp.exec.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.checkConfigValid = void 0);
+            var n = {
+              endpoint: function (e) {
+                {
+                  if ('string' == typeof e) return /^[a-zA-Z0-9._:/-]+$/.test(e);
+                  if (e.host) return /^[a-zA-Z0-9._:/-]+$/.test(e.host);
+                }
+                return !1;
+              },
+              region: /^[a-zA-Z0-9\-_]+$/
+            };
+            r.checkConfigValid = function (e, t) {
+              if (n[t])
+                if (!(n[t] instanceof Function ? n[t](e) : n[t].test(e)))
+                  throw new Error('The '.concat(t, ' must be conform to the specifications'));
+            };
+          },
+          { 'core-js/modules/es.regexp.exec.js': 299 }
+        ],
+        53: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.concat.js'),
+              e('core-js/modules/es.object.entries.js'),
+              e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.checkObjectTag = void 0);
+            var n = e('./checkValid').checkValid,
+              s = e('./isObject').isObject,
+              e = [
+                {
+                  validator: function (e) {
+                    if ('string' != typeof e) throw new Error('the key and value of the tag must be String');
+                  }
+                },
+                {
+                  pattern: /^[a-zA-Z0-9 +-=._:/]+$/,
+                  msg: 'tag can contain letters, numbers, spaces, and the following symbols: plus sign (+), hyphen (-), equal sign (=), period (.), underscore (_), colon (:), and forward slash (/)'
+                }
+              ],
+              i = {
+                key: [].concat(e, [{ pattern: /^.{1,128}$/, msg: 'tag key can be a maximum of 128 bytes in length' }]),
+                value: [].concat(e, [
+                  { pattern: /^.{0,256}$/, msg: 'tag value can be a maximum of 256 bytes in length' }
+                ])
+              };
+            r.checkObjectTag = function (e) {
+              if (!s(e)) throw new Error('tag must be Object');
+              if (10 < (e = Object.entries(e)).length) throw new Error('maximum of 10 tags for a object');
+              var r = ['key', 'value'];
+              e.forEach(function (e) {
+                e.forEach(function (e, t) {
+                  n(e, i[r[t]]);
+                });
+              });
+            };
+          },
+          {
+            './checkValid': 54,
+            './isObject': 68,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.object.entries.js': 285,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        54: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.checkValid = void 0),
+              (r.checkValid = function (t, e) {
+                e.forEach(function (e) {
+                  if (e.validator) e.validator(t);
+                  else if (e.pattern && !e.pattern.test(t)) throw new Error(e.msg);
+                });
+              });
+          },
+          {
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        55: [
+          function (e, t, r) {
+            !function (v) {
+              !function () {
+                'use strict';
+                e('core-js/modules/es.array.includes.js'),
+                  e('core-js/modules/es.string.includes.js'),
+                  e('core-js/modules/es.object.assign.js'),
+                  e('core-js/modules/es.array.concat.js'),
+                  Object.defineProperty(r, '__esModule', { value: !0 }),
+                  (r.createRequest = void 0);
+                var c = e('./../../../shims/crypto/crypto.js'),
+                  l = e('debug')('ali-oss'),
+                  u = e('mime'),
+                  p = e('dateformat'),
+                  f = e('copy-to'),
+                  d = e('path'),
+                  h = e('./encoder').encoder,
+                  m = e('./isIP').isIP,
+                  y = e('./setRegion').setRegion,
+                  b = e('../client/getReqUrl').getReqUrl;
+                function g(e, t) {
+                  return e[t] || e[t.toLowerCase()];
+                }
+                r.createRequest = function (e) {
+                  var t,
+                    r = new Date(),
+                    n =
+                      (this.options.amendTimeSkewed && (r = +new Date() + this.options.amendTimeSkewed),
+                      { 'x-oss-date': p(r, "UTC:ddd, dd mmm yyyy HH:MM:ss 'GMT'") }),
+                    s =
+                      ('undefined' != typeof window && (n['x-oss-user-agent'] = this.userAgent),
+                      this.userAgent.includes('nodejs') && (n['User-Agent'] = this.userAgent),
+                      this.options.isRequestPay && Object.assign(n, { 'x-oss-request-payer': 'requester' }),
+                      this.options.stsToken && (n['x-oss-security-token'] = this.options.stsToken),
+                      f(e.headers).to(n),
+                      g(n, 'Content-Type') ||
+                        (e.mime && 0 < e.mime.indexOf('/')
+                          ? (n['Content-Type'] = e.mime)
+                          : (n['Content-Type'] = u.getType(e.mime || d.extname(e.object || '')))),
+                      g(n, 'Content-Type') || (delete (r = n)[(i = 'Content-Type')], delete r[i.toLowerCase()]),
+                      e.content &&
+                        (e.disabledMD5 ||
+                          (e.headers && e.headers['Content-MD5']
+                            ? (n['Content-MD5'] = e.headers['Content-MD5'])
+                            : (n['Content-MD5'] = c
+                                .createHash('md5')
+                                .update(v.from(e.content, 'utf8'))
+                                .digest('base64'))),
+                        n['Content-Length'] || (n['Content-Length'] = e.content.length)),
+                      Object.prototype.hasOwnProperty);
+                  for (t in n) n[t] && s.call(n, t) && (n[t] = h(String(n[t]), this.options.headerEncoding));
+                  var i,
+                    r = this._getResource(e),
+                    o =
+                      ((n.authorization = this.authorization(e.method, r, e.subres, n, this.options.headerEncoding)),
+                      m(this.options.endpoint.hostname) &&
+                        ((r = (i = this.options).region),
+                        (o = i.internal),
+                        (a = i.secure),
+                        (r = y(r, o, a)),
+                        (n.host = ''.concat(e.bucket, '.').concat(r.host))),
+                      b.bind(this)(e)),
+                    a =
+                      (l('request %s %s, with headers %j, !!stream: %s', e.method, o, n, !!e.stream),
+                      e.timeout || this.options.timeout),
+                    r = {
+                      method: e.method,
+                      content: e.content,
+                      stream: e.stream,
+                      headers: n,
+                      timeout: a,
+                      writeStream: e.writeStream,
+                      customResponse: e.customResponse,
+                      ctx: e.ctx || this.ctx
+                    };
+                  return (
+                    this.agent && (r.agent = this.agent),
+                    this.httpsAgent && (r.httpsAgent = this.httpsAgent),
+                    (r.enableProxy = !!this.options.enableProxy),
+                    (r.proxy = this.options.proxy || null),
+                    { url: o, params: r }
+                  );
+                };
+              }.call(this);
+            }.call(this, e('buffer').Buffer);
+          },
+          {
+            '../client/getReqUrl': 25,
+            './../../../shims/crypto/crypto.js': 435,
+            './encoder': 58,
+            './isIP': 67,
+            './setRegion': 73,
+            buffer: 89,
+            'copy-to': 91,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.string.includes.js': 301,
+            dateformat: 341,
+            debug: 439,
+            mime: 359,
+            path: 363
+          }
+        ],
+        56: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js'),
+              e('core-js/modules/es.object.entries.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.string.replace.js'),
+              e('core-js/modules/es.array.includes.js'),
+              e('core-js/modules/es.object.keys.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.dataFix = void 0);
+            var l = e('./isObject'),
+              u = ['true', 'TRUE', '1', 1],
+              p = ['false', 'FALSE', '0', 0];
+            r.dataFix = function e(r, t, n) {
+              var s, i, o, a, c;
+              if (l.isObject(r))
+                return (
+                  (s = t.remove),
+                  (s = void 0 === s ? [] : s),
+                  (i = t.rename),
+                  (i = void 0 === i ? {} : i),
+                  (o = t.camel),
+                  (o = void 0 === o ? [] : o),
+                  (a = t.bool),
+                  (a = void 0 === a ? [] : a),
+                  (t = t.lowerFirst),
+                  (t = void 0 !== t && t),
+                  s.forEach(function (e) {
+                    return delete r[e];
+                  }),
+                  Object.entries(i).forEach(function (e) {
+                    r[e[0]] && !r[e[1]] && ((r[e[1]] = r[e[0]]), delete r[e[0]]);
+                  }),
+                  o.forEach(function (e) {
+                    var t;
+                    r[e] &&
+                      ((t = e
+                        .replace(/^(.)/, function (e) {
+                          return e.toLowerCase();
+                        })
+                        .replace(/-(\w)/g, function (e, t) {
+                          return t.toUpperCase();
+                        })),
+                      r[t] || (r[t] = r[e]));
+                  }),
+                  a.forEach(function (e) {
+                    r[e] = !!(e = r[e]) && (!!u.includes(e) || (!p.includes(e) && e));
+                  }),
+                  'function' == typeof n && n(r),
+                  (c = r),
+                  t &&
+                    Object.keys(c).forEach(function (e) {
+                      var t = e.replace(/^\w/, function (e) {
+                        return e.toLowerCase();
+                      });
+                      void 0 === c[t] && ((c[t] = c[e]), delete c[e]);
+                    }),
+                  e
+                );
+            };
+          },
+          {
+            './isObject': 68,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.object.entries.js': 285,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        57: [
+          function (e, t, n) {
+            'use strict';
+            var r = e('@babel/runtime/helpers/interopRequireDefault'),
+              o =
+                (e('core-js/modules/es.array.slice.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                r(e('@babel/runtime/helpers/typeof'))),
+              a =
+                (Object.defineProperty(n, '__esModule', { value: !0 }),
+                (n.deepCopyWith = n.deepCopy = void 0),
+                e('./isBuffer'));
+            (n.deepCopy = function (t) {
+              if (null === t || 'object' !== (0, o.default)(t)) return t;
+              if (a.isBuffer(t)) return t.slice();
+              var r = Array.isArray(t) ? [] : {};
+              return (
+                Object.keys(t).forEach(function (e) {
+                  r[e] = n.deepCopy(t[e]);
+                }),
+                r
+              );
+            }),
+              (n.deepCopyWith = function (e, i) {
+                return i
+                  ? (function t(r, e, n) {
+                      e = i(r, e, n);
+                      if (void 0 !== e) return e;
+                      if (null === r || 'object' !== (0, o.default)(r)) return r;
+                      if (a.isBuffer(r)) return r.slice();
+                      var s = Array.isArray(r) ? [] : {};
+                      return (
+                        Object.keys(r).forEach(function (e) {
+                          s[e] = t(r[e], e, r);
+                        }),
+                        s
+                      );
+                    })(e, '', null)
+                  : n.deepCopy(e);
+              });
+          },
+          {
+            './isBuffer': 64,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        58: [
+          function (e, t, r) {
+            !function (t) {
+              !function () {
+                'use strict';
+                e('core-js/modules/es.object.to-string.js'),
+                  e('core-js/modules/es.regexp.to-string.js'),
+                  Object.defineProperty(r, '__esModule', { value: !0 }),
+                  (r.encoder = void 0),
+                  (r.encoder = function (e) {
+                    return 'utf-8' === (1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : 'utf-8')
+                      ? e
+                      : t.from(e).toString('latin1');
+                  });
+              }.call(this);
+            }.call(this, e('buffer').Buffer);
+          },
+          { buffer: 89, 'core-js/modules/es.object.to-string.js': 290, 'core-js/modules/es.regexp.to-string.js': 300 }
+        ],
+        59: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.map.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.string.replace.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.formatInventoryConfig = void 0);
+            var n = e('../utils/dataFix'),
+              s = e('../utils/isObject'),
+              i = e('../utils/isArray'),
+              o = e('../utils/formatObjKey');
+            function a(e) {
+              return (
+                n.dataFix(e, { bool: ['IsEnabled'] }, function (e) {
+                  var t;
+                  (e.prefix = e.Filter.Prefix),
+                    delete e.Filter,
+                    (e.OSSBucketDestination = e.Destination.OSSBucketDestination),
+                    (e.OSSBucketDestination.rolename = e.OSSBucketDestination.RoleArn.replace(/.*\//, '')),
+                    delete e.OSSBucketDestination.RoleArn,
+                    (e.OSSBucketDestination.bucket = e.OSSBucketDestination.Bucket.replace(/.*:::/, '')),
+                    delete e.OSSBucketDestination.Bucket,
+                    delete e.Destination,
+                    (e.frequency = e.Schedule.Frequency),
+                    delete e.Schedule.Frequency,
+                    null != (t = null == e ? void 0 : e.OptionalFields) &&
+                      t.Field &&
+                      !i.isArray(null == (t = e.OptionalFields) ? void 0 : t.Field) &&
+                      (e.OptionalFields.Field = [e.OptionalFields.Field]);
+                }),
+                (e = o.formatObjKey(e, 'firstLowerCase', { exclude: ['OSSBucketDestination', 'SSE-OSS', 'SSE-KMS'] }))
+              );
+            }
+            r.formatInventoryConfig = function (e) {
+              return (
+                1 < arguments.length && void 0 !== arguments[1] && arguments[1] && s.isObject(e) && (e = [e]),
+                (e = i.isArray(e) ? e.map(a) : a(e))
+              );
+            };
+          },
+          {
+            '../utils/dataFix': 56,
+            '../utils/formatObjKey': 60,
+            '../utils/isArray': 62,
+            '../utils/isObject': 68,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.replace.js': 304
+          }
+        ],
+        60: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              o =
+                (e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/web.dom-collections.for-each.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.array.includes.js'),
+                e('core-js/modules/es.string.includes.js'),
+                e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.string.replace.js'),
+                n(e('@babel/runtime/helpers/typeof')));
+            Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.formatObjKey = void 0),
+              (r.formatObjKey = function t(r, n, s) {
+                if (null === r || 'object' !== (0, o.default)(r)) return r;
+                if (Array.isArray(r)) for (var i = [], e = 0; e < r.length; e++) i.push(t(r[e], n, s));
+                else
+                  (i = {}),
+                    Object.keys(r).forEach(function (e) {
+                      i[
+                        (function (e, t, r) {
+                          return (
+                            (r && r.exclude && r.exclude.includes(e)) ||
+                              ('firstUpperCase' === t
+                                ? (e = e.replace(/^./, function (e) {
+                                    return e.toUpperCase();
+                                  }))
+                                : 'firstLowerCase' === t &&
+                                  (e = e.replace(/^./, function (e) {
+                                    return e.toLowerCase();
+                                  }))),
+                            e
+                          );
+                        })(e, n, s)
+                      ] = t(r[e], n, s);
+                    });
+                return i;
+              });
+          },
+          {
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            'core-js/modules/es.array.includes.js': 274,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.includes.js': 301,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        61: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.regexp.exec.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.getStrBytesCount = void 0),
+              (r.getStrBytesCount = function (e) {
+                for (var t = 0, r = 0; r < e.length; r++) {
+                  var n = e.charAt(r);
+                  /^[\u00-\uff]$/.test(n) ? (t += 1) : (t += 2);
+                }
+                return t;
+              });
+          },
+          { 'core-js/modules/es.regexp.exec.js': 299 }
+        ],
+        62: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isArray = void 0),
+              (r.isArray = function (e) {
+                return '[object Array]' === Object.prototype.toString.call(e);
+              });
+          },
+          { 'core-js/modules/es.object.to-string.js': 290 }
+        ],
+        63: [
+          function (e, t, r) {
+            'use strict';
+            Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isBlob = void 0),
+              (r.isBlob = function (e) {
+                return 'undefined' != typeof Blob && e instanceof Blob;
+              });
+          },
+          {}
+        ],
+        64: [
+          function (e, t, r) {
+            !function (t) {
+              !function () {
+                'use strict';
+                Object.defineProperty(r, '__esModule', { value: !0 }),
+                  (r.isBuffer = void 0),
+                  (r.isBuffer = function (e) {
+                    return t.isBuffer(e);
+                  });
+              }.call(this);
+            }.call(this, { isBuffer: e('../../../node_modules/is-buffer/index.js') });
+          },
+          { '../../../node_modules/is-buffer/index.js': 354 }
+        ],
+        65: [
+          function (e, t, r) {
+            'use strict';
+            Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isFile = void 0),
+              (r.isFile = function (e) {
+                return 'undefined' != typeof File && e instanceof File;
+              });
+          },
+          {}
+        ],
+        66: [
+          function (e, t, r) {
+            'use strict';
+            Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isFunction = void 0),
+              (r.isFunction = function (e) {
+                return 'function' == typeof e;
+              });
+          },
+          {}
+        ],
+        67: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.regexp.exec.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isIP = void 0),
+              (r.isIP = function (e) {
+                return (
+                  /^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/.test(e) ||
+                  /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(
+                    e
+                  )
+                );
+              });
+          },
+          { 'core-js/modules/es.regexp.exec.js': 299 }
+        ],
+        68: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.isObject = void 0),
+              (r.isObject = function (e) {
+                return '[object Object]' === Object.prototype.toString.call(e);
+              });
+          },
+          { 'core-js/modules/es.object.to-string.js': 290 }
+        ],
+        69: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js'),
+              e('core-js/modules/es.object.keys.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.lowercaseKeyHeader = void 0);
+            var n = e('./isObject');
+            r.lowercaseKeyHeader = function (t) {
+              var r = {};
+              return (
+                n.isObject(t) &&
+                  Object.keys(t).forEach(function (e) {
+                    r[e.toLowerCase()] = t[e];
+                  }),
+                r
+              );
+            };
+          },
+          {
+            './isObject': 68,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        70: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.string.replace.js'),
+              e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/web.dom-collections.for-each.js'),
+              e('core-js/modules/es.object.keys.js'),
+              e('core-js/modules/es.array.concat.js'),
+              e('core-js/modules/es.array.join.js'),
+              e('core-js/modules/es.array.map.js'),
+              e('core-js/modules/es.regexp.to-string.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.obj2xml = void 0);
+            var s = e('./formatObjKey');
+            function i(e) {
+              return Object.prototype.toString
+                .call(e)
+                .replace(/(.*? |])/g, '')
+                .toLowerCase();
+            }
+            r.obj2xml = function r(e, t) {
+              var n = '';
+              return (
+                t && t.headers && (n = '<?xml version="1.0" encoding="UTF-8"?>\n'),
+                'object' === i((e = t && t.firstUpperCase ? s.formatObjKey(e, 'firstUpperCase') : e))
+                  ? Object.keys(e).forEach(function (t) {
+                      'undefined' !== i(e[t]) &&
+                        'null' !== i(e[t]) &&
+                        ('string' === i(e[t]) || 'number' === i(e[t])
+                          ? (n += '<'.concat(t, '>').concat(e[t], '</').concat(t, '>'))
+                          : 'object' === i(e[t])
+                          ? (n += '<'.concat(t, '>').concat(r(e[t]), '</').concat(t, '>'))
+                          : 'array' === i(e[t])
+                          ? (n += e[t]
+                              .map(function (e) {
+                                return '<'.concat(t, '>').concat(r(e), '</').concat(t, '>');
+                              })
+                              .join(''))
+                          : (n += '<'.concat(t, '>').concat(e[t].toString(), '</').concat(t, '>')));
+                    })
+                  : (n += e.toString()),
+                n
+              );
+            };
+          },
+          {
+            './formatObjKey': 60,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.join.js': 276,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/web.dom-collections.for-each.js': 338
+          }
+        ],
+        71: [
+          function (e, t, r) {
+            'use strict';
+            function i(e, t) {
+              var r,
+                n = ('undefined' != typeof Symbol && e[Symbol.iterator]) || e['@@iterator'];
+              if (!n) {
+                if (
+                  Array.isArray(e) ||
+                  (n = (function (e, t) {
+                    if (e) {
+                      if ('string' == typeof e) return a(e, t);
+                      var r = Object.prototype.toString.call(e).slice(8, -1);
+                      return 'Map' === (r = 'Object' === r && e.constructor ? e.constructor.name : r) || 'Set' === r
+                        ? Array.from(e)
+                        : 'Arguments' === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
+                        ? a(e, t)
+                        : void 0;
+                    }
+                  })(e)) ||
+                  (t && e && 'number' == typeof e.length)
+                )
+                  return (
+                    n && (e = n),
+                    (r = 0),
+                    {
+                      s: (t = function () {}),
+                      n: function () {
+                        return r >= e.length ? { done: !0 } : { done: !1, value: e[r++] };
+                      },
+                      e: function (e) {
+                        throw e;
+                      },
+                      f: t
+                    }
+                  );
+                throw new TypeError(
+                  'Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.'
+                );
+              }
+              var s,
+                i = !0,
+                o = !1;
+              return {
+                s: function () {
+                  n = n.call(e);
+                },
+                n: function () {
+                  var e = n.next();
+                  return (i = e.done), e;
+                },
+                e: function (e) {
+                  (o = !0), (s = e);
+                },
+                f: function () {
+                  try {
+                    i || null == n.return || n.return();
+                  } finally {
+                    if (o) throw s;
+                  }
+                }
+              };
+            }
+            function a(e, t) {
+              (null == t || t > e.length) && (t = e.length);
+              for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
+              return n;
+            }
+            e('core-js/modules/es.array.slice.js'),
+              e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/es.function.name.js'),
+              e('core-js/modules/es.array.from.js'),
+              e('core-js/modules/es.string.iterator.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.symbol.js'),
+              e('core-js/modules/es.symbol.description.js'),
+              e('core-js/modules/es.symbol.iterator.js'),
+              e('core-js/modules/es.array.iterator.js'),
+              e('core-js/modules/web.dom-collections.iterator.js'),
+              e('core-js/modules/es.object.assign.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.omit = void 0),
+              (r.omit = function (e, t) {
+                var r,
+                  n = Object.assign({}, e),
+                  s = i(t);
+                try {
+                  for (s.s(); !(r = s.n()).done; ) delete n[r.value];
+                } catch (e) {
+                  s.e(e);
+                } finally {
+                  s.f();
+                }
+                return n;
+              });
+          },
+          {
+            'core-js/modules/es.array.from.js': 273,
+            'core-js/modules/es.array.iterator.js': 275,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.iterator.js': 302,
+            'core-js/modules/es.symbol.description.js': 309,
+            'core-js/modules/es.symbol.iterator.js': 311,
+            'core-js/modules/es.symbol.js': 312,
+            'core-js/modules/web.dom-collections.iterator.js': 339
+          }
+        ],
+        72: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/es.promise.js'),
+              Object.defineProperty(r, '__esModule', { value: !0 }),
+              (r.retry = void 0),
+              (r.retry = function (i, o) {
+                var e = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : {},
+                  a = 0,
+                  t = e.retryDelay,
+                  c = void 0 === t ? 500 : t,
+                  l =
+                    void 0 === (t = e.errorHandler)
+                      ? function () {
+                          return !0;
+                        }
+                      : t;
+                return function n() {
+                  for (var e = arguments.length, s = new Array(e), t = 0; t < e; t++) s[t] = arguments[t];
+                  return new Promise(function (t, r) {
+                    i.apply(void 0, s)
+                      .then(function (e) {
+                        (a = 0), t(e);
+                      })
+                      .catch(function (e) {
+                        a < o && l(e)
+                          ? (a++,
+                            setTimeout(function () {
+                              t(n.apply(void 0, s));
+                            }, c))
+                          : ((a = 0), r(e));
+                      });
+                  });
+                };
+              });
+          },
+          { 'core-js/modules/es.object.to-string.js': 290, 'core-js/modules/es.promise.js': 294 }
+        ],
+        73: [
+          function (e, t, r) {
+            'use strict';
+            var n = function (e) {
+                return e && e.__esModule ? e : { default: e };
+              },
+              s = (Object.defineProperty(r, '__esModule', { value: !0 }), (r.setRegion = void 0), n(e('url'))),
+              i = e('./checkConfigValid');
+            r.setRegion = function (e) {
+              var t = 1 < arguments.length && void 0 !== arguments[1] && arguments[1],
+                r = 2 < arguments.length && void 0 !== arguments[2] && arguments[2],
+                r = (i.checkConfigValid(e, 'region'), r ? 'https://' : 'http://'),
+                t = t ? '-internal.aliyuncs.com' : '.aliyuncs.com',
+                n = 'vpc100-oss-cn-';
+              return e.substr(0, n.length) === n && (t = '.aliyuncs.com'), s.default.parse(r + e + t);
+            };
+          },
+          { './checkConfigValid': 52, url: 446 }
+        ],
+        74: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault'),
+              s = n(e('@babel/runtime/regenerator')),
+              i =
+                (e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.object.to-string.js'),
+                e('core-js/modules/es.array.find.js'),
+                e('core-js/modules/es.object.assign.js'),
+                n(e('@babel/runtime/helpers/asyncToGenerator'))),
+              o =
+                (Object.defineProperty(r, '__esModule', { value: !0 }),
+                (r.checkCredentials = r.setSTSToken = void 0),
+                e('./formatObjKey'));
+            function a() {
+              return (a = (0, i.default)(
+                s.default.mark(function e() {
+                  var t, r;
+                  return s.default.wrap(
+                    function (e) {
+                      for (;;)
+                        switch ((e.prev = e.next)) {
+                          case 0:
+                            if ((this.options || (this.options = {}), (t = new Date()), !this.stsTokenFreshTime)) {
+                              e.next = 14;
+                              break;
+                            }
+                            if (+t - this.stsTokenFreshTime >= this.options.refreshSTSTokenInterval)
+                              return (this.stsTokenFreshTime = t), (e.next = 7), this.options.refreshSTSToken();
+                            e.next = 12;
+                            break;
+                          case 7:
+                            (r = e.sent),
+                              (r = o.formatObjKey(r, 'firstLowerCase')).securityToken && (r.stsToken = r.securityToken),
+                              c(r),
+                              Object.assign(this.options, r);
+                          case 12:
+                            e.next = 15;
+                            break;
+                          case 14:
+                            this.stsTokenFreshTime = t;
+                          case 15:
+                            return e.abrupt('return', null);
+                          case 16:
+                          case 'end':
+                            return e.stop();
+                        }
+                    },
+                    e,
+                    this
+                  );
+                })
+              )).apply(this, arguments);
+            }
+            function c(e) {
+              var r = Object.keys(e);
+              ['accessKeySecret', 'accessKeyId', 'stsToken'].forEach(function (t) {
+                if (
+                  !r.find(function (e) {
+                    return e === t;
+                  })
+                )
+                  throw Error('refreshSTSToken must return contains '.concat(t));
+              });
+            }
+            (r.setSTSToken = function () {
+              return a.apply(this, arguments);
+            }),
+              (r.checkCredentials = c);
+          },
+          {
+            './formatObjKey': 60,
+            '@babel/runtime/helpers/asyncToGenerator': 75,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/regenerator': 79,
+            'core-js/modules/es.array.find.js': 272,
+            'core-js/modules/es.object.assign.js': 284,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290
+          }
+        ],
+        75: [
+          function (e, t, r) {
+            function c(e, t, r, n, s, i, o) {
+              try {
+                var a = e[i](o),
+                  c = a.value;
+              } catch (e) {
+                return void r(e);
+              }
+              a.done ? t(c) : Promise.resolve(c).then(n, s);
+            }
+            (t.exports = function (a) {
+              return function () {
+                var e = this,
+                  o = arguments;
+                return new Promise(function (t, r) {
+                  var n = a.apply(e, o);
+                  function s(e) {
+                    c(n, t, r, s, i, 'next', e);
+                  }
+                  function i(e) {
+                    c(n, t, r, s, i, 'throw', e);
+                  }
+                  s(void 0);
+                });
+              };
+            }),
+              (t.exports.__esModule = !0),
+              (t.exports.default = t.exports);
+          },
+          {}
+        ],
+        76: [
+          function (e, t, r) {
+            (t.exports = function (e, t, r) {
+              return (
+                t in e
+                  ? Object.defineProperty(e, t, { value: r, enumerable: !0, configurable: !0, writable: !0 })
+                  : (e[t] = r),
+                e
+              );
+            }),
+              (t.exports.__esModule = !0),
+              (t.exports.default = t.exports);
+          },
+          {}
+        ],
+        77: [
+          function (e, t, r) {
+            (t.exports = function (e) {
+              return e && e.__esModule ? e : { default: e };
+            }),
+              (t.exports.__esModule = !0),
+              (t.exports.default = t.exports);
+          },
+          {}
+        ],
+        78: [
+          function (e, t, r) {
+            function n(e) {
+              return (
+                (t.exports = n =
+                  'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
+                    ? function (e) {
+                        return typeof e;
+                      }
+                    : function (e) {
+                        return e && 'function' == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype
+                          ? 'symbol'
+                          : typeof e;
+                      }),
+                (t.exports.__esModule = !0),
+                (t.exports.default = t.exports),
+                n(e)
+              );
+            }
+            (t.exports = n), (t.exports.__esModule = !0), (t.exports.default = t.exports);
+          },
+          {}
+        ],
+        79: [
+          function (e, t, r) {
+            t.exports = e('regenerator-runtime');
+          },
+          { 'regenerator-runtime': 384 }
+        ],
+        80: [
+          function (e, t, r) {
+            function n() {}
+            (t.exports = n), (t.exports.HttpsAgent = n);
+          },
+          {}
+        ],
+        81: [
+          function (x, T, e) {
+            !function (f) {
+              !function () {
+                'use strict';
+                var e = x('object-assign');
+                function d(e, t) {
+                  if (e === t) return 0;
+                  for (var r = e.length, n = t.length, s = 0, i = Math.min(r, n); s < i; ++s)
+                    if (e[s] !== t[s]) {
+                      (r = e[s]), (n = t[s]);
+                      break;
+                    }
+                  return r < n ? -1 : n < r ? 1 : 0;
+                }
+                function h(e) {
+                  return f.Buffer && 'function' == typeof f.Buffer.isBuffer
+                    ? f.Buffer.isBuffer(e)
+                    : !(null == e || !e._isBuffer);
+                }
+                var m = x('util/'),
+                  n = Object.prototype.hasOwnProperty,
+                  y = Array.prototype.slice,
+                  t = 'foo' === function () {}.name;
+                function b(e) {
+                  return Object.prototype.toString.call(e);
+                }
+                function g(e) {
+                  return (
+                    !h(e) &&
+                    'function' == typeof f.ArrayBuffer &&
+                    ('function' == typeof ArrayBuffer.isView
+                      ? ArrayBuffer.isView(e)
+                      : e && (e instanceof DataView || !!(e.buffer && e.buffer instanceof ArrayBuffer)))
+                  );
+                }
+                var i = (T.exports = l),
+                  r = /\s*function\s+([^\(\s]*)\s*/;
+                function s(e) {
+                  if (m.isFunction(e)) {
+                    if (t) return e.name;
+                    e = e.toString().match(r);
+                    return e && e[1];
+                  }
+                }
+                function o(e, t) {
+                  return 'string' != typeof e || e.length < t ? e : e.slice(0, t);
+                }
+                function a(e) {
+                  if (t || !m.isFunction(e)) return m.inspect(e);
+                  e = s(e);
+                  return '[Function' + (e ? ': ' + e : '') + ']';
+                }
+                function c(e, t, r, n, s) {
+                  throw new i.AssertionError({
+                    message: r,
+                    actual: e,
+                    expected: t,
+                    operator: n,
+                    stackStartFunction: s
+                  });
+                }
+                function l(e, t) {
+                  e || c(e, !0, t, '==', i.ok);
+                }
+                function v(e, t, r, n) {
+                  if (e === t) return !0;
+                  if (h(e) && h(t)) return 0 === d(e, t);
+                  if (m.isDate(e) && m.isDate(t)) return e.getTime() === t.getTime();
+                  if (m.isRegExp(e) && m.isRegExp(t))
+                    return (
+                      e.source === t.source &&
+                      e.global === t.global &&
+                      e.multiline === t.multiline &&
+                      e.lastIndex === t.lastIndex &&
+                      e.ignoreCase === t.ignoreCase
+                    );
+                  if ((null !== e && 'object' == typeof e) || (null !== t && 'object' == typeof t)) {
+                    if (g(e) && g(t) && b(e) === b(t) && !(e instanceof Float32Array || e instanceof Float64Array))
+                      return 0 === d(new Uint8Array(e.buffer), new Uint8Array(t.buffer));
+                    if (h(e) !== h(t)) return !1;
+                    var s = (n = n || { actual: [], expected: [] }).actual.indexOf(e);
+                    if (-1 !== s && s === n.expected.indexOf(t)) return !0;
+                    n.actual.push(e), n.expected.push(t);
+                    var i = e,
+                      o = t,
+                      a = r,
+                      c = n;
+                    if (null == i || null == o) return !1;
+                    if (m.isPrimitive(i) || m.isPrimitive(o)) return i === o;
+                    if (a && Object.getPrototypeOf(i) !== Object.getPrototypeOf(o)) return !1;
+                    (s = j(i)), (n = j(o));
+                    if ((s && !n) || (!s && n)) return !1;
+                    if (s) return (i = y.call(i)), (o = y.call(o)), v(i, o, a);
+                    var l,
+                      u,
+                      p = w(i),
+                      f = w(o);
+                    if (p.length !== f.length) return !1;
+                    for (p.sort(), f.sort(), u = p.length - 1; 0 <= u; u--) if (p[u] !== f[u]) return !1;
+                    for (u = p.length - 1; 0 <= u; u--) if (((l = p[u]), !v(i[l], o[l], a, c))) return !1;
+                    return !0;
+                  }
+                  return r ? e === t : e == t;
+                }
+                function j(e) {
+                  return '[object Arguments]' == Object.prototype.toString.call(e);
+                }
+                function u(e, t) {
+                  if (e && t) {
+                    if ('[object RegExp]' == Object.prototype.toString.call(t)) return t.test(e);
+                    try {
+                      if (e instanceof t) return 1;
+                    } catch (e) {}
+                    return Error.isPrototypeOf(t) ? void 0 : !0 === t.call({}, e);
+                  }
+                }
+                function p(e, t, r, n) {
+                  if ('function' != typeof t) throw new TypeError('"block" argument must be a function');
+                  'string' == typeof r && ((n = r), (r = null)),
+                    (t = (function (e) {
+                      var t;
+                      try {
+                        e();
+                      } catch (e) {
+                        t = e;
+                      }
+                      return t;
+                    })(t)),
+                    (n = (r && r.name ? ' (' + r.name + ').' : '.') + (n ? ' ' + n : '.')),
+                    e && !t && c(t, r, 'Missing expected exception' + n);
+                  var s = 'string' == typeof n,
+                    i = !e && t && !r;
+                  if (
+                    (((!e && m.isError(t) && s && u(t, r)) || i) && c(t, r, 'Got unwanted exception' + n),
+                    (e && t && r && !u(t, r)) || (!e && t))
+                  )
+                    throw t;
+                }
+                (i.AssertionError = function (e) {
+                  (this.name = 'AssertionError'),
+                    (this.actual = e.actual),
+                    (this.expected = e.expected),
+                    (this.operator = e.operator),
+                    e.message
+                      ? ((this.message = e.message), (this.generatedMessage = !1))
+                      : ((this.message = o(a((r = this).actual), 128) + ' ' + r.operator + ' ' + o(a(r.expected), 128)),
+                        (this.generatedMessage = !0));
+                  var t,
+                    r = e.stackStartFunction || c;
+                  Error.captureStackTrace
+                    ? Error.captureStackTrace(this, r)
+                    : (e = new Error()).stack &&
+                      ((e = e.stack),
+                      (t = s(r)),
+                      0 <= (t = e.indexOf('\n' + t)) && ((t = e.indexOf('\n', t + 1)), (e = e.substring(t + 1))),
+                      (this.stack = e));
+                }),
+                  m.inherits(i.AssertionError, Error),
+                  (i.fail = c),
+                  (i.ok = l),
+                  (i.equal = function (e, t, r) {
+                    e != t && c(e, t, r, '==', i.equal);
+                  }),
+                  (i.notEqual = function (e, t, r) {
+                    e == t && c(e, t, r, '!=', i.notEqual);
+                  }),
+                  (i.deepEqual = function (e, t, r) {
+                    v(e, t, !1) || c(e, t, r, 'deepEqual', i.deepEqual);
+                  }),
+                  (i.deepStrictEqual = function (e, t, r) {
+                    v(e, t, !0) || c(e, t, r, 'deepStrictEqual', i.deepStrictEqual);
+                  }),
+                  (i.notDeepEqual = function (e, t, r) {
+                    v(e, t, !1) && c(e, t, r, 'notDeepEqual', i.notDeepEqual);
+                  }),
+                  (i.notDeepStrictEqual = function e(t, r, n) {
+                    v(t, r, !0) && c(t, r, n, 'notDeepStrictEqual', e);
+                  }),
+                  (i.strictEqual = function (e, t, r) {
+                    e !== t && c(e, t, r, '===', i.strictEqual);
+                  }),
+                  (i.notStrictEqual = function (e, t, r) {
+                    e === t && c(e, t, r, '!==', i.notStrictEqual);
+                  }),
+                  (i.throws = function (e, t, r) {
+                    p(!0, e, t, r);
+                  }),
+                  (i.doesNotThrow = function (e, t, r) {
+                    p(!1, e, t, r);
+                  }),
+                  (i.ifError = function (e) {
+                    if (e) throw e;
+                  }),
+                  (i.strict = e(
+                    function e(t, r) {
+                      t || c(t, !0, r, '==', e);
+                    },
+                    i,
+                    {
+                      equal: i.strictEqual,
+                      deepEqual: i.deepStrictEqual,
+                      notEqual: i.notStrictEqual,
+                      notDeepEqual: i.notDeepStrictEqual
+                    }
+                  )),
+                  (i.strict.strict = i.strict);
+                var w =
+                  Object.keys ||
+                  function (e) {
+                    var t,
+                      r = [];
+                    for (t in e) n.call(e, t) && r.push(t);
+                    return r;
+                  };
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          { 'object-assign': 362, 'util/': 84 }
+        ],
+        82: [
+          function (e, t, r) {
+            'function' == typeof Object.create
+              ? (t.exports = function (e, t) {
+                  (e.super_ = t),
+                    (e.prototype = Object.create(t.prototype, {
+                      constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 }
+                    }));
+                })
+              : (t.exports = function (e, t) {
+                  e.super_ = t;
+                  function r() {}
+                  (r.prototype = t.prototype), (e.prototype = new r()), (e.prototype.constructor = e);
+                });
+          },
+          {}
+        ],
+        83: [
+          function (e, t, r) {
+            t.exports = function (e) {
+              return (
+                e &&
+                'object' == typeof e &&
+                'function' == typeof e.copy &&
+                'function' == typeof e.fill &&
+                'function' == typeof e.readUInt8
+              );
+            };
+          },
+          {}
+        ],
+        84: [
+          function (_, e, S) {
+            !function (k, E) {
+              !function () {
+                var e,
+                  a = /%[sdj%]/g,
+                  n =
+                    ((S.format = function (e) {
+                      if (!b(e)) {
+                        for (var t = [], r = 0; r < arguments.length; r++) t.push(c(arguments[r]));
+                        return t.join(' ');
+                      }
+                      for (
+                        var r = 1,
+                          n = arguments,
+                          s = n.length,
+                          i = String(e).replace(a, function (e) {
+                            if ('%%' === e) return '%';
+                            if (s <= r) return e;
+                            switch (e) {
+                              case '%s':
+                                return String(n[r++]);
+                              case '%d':
+                                return Number(n[r++]);
+                              case '%j':
+                                try {
+                                  return JSON.stringify(n[r++]);
+                                } catch (e) {
+                                  return '[Circular]';
+                                }
+                              default:
+                                return e;
+                            }
+                          }),
+                          o = n[r];
+                        r < s;
+                        o = n[++r]
+                      )
+                        m(o) || !l(o) ? (i += ' ' + o) : (i += ' ' + c(o));
+                      return i;
+                    }),
+                    (S.deprecate = function (e, t) {
+                      if (g(E.process))
+                        return function () {
+                          return S.deprecate(e, t).apply(this, arguments);
+                        };
+                      if (!0 === k.noDeprecation) return e;
+                      var r = !1;
+                      return function () {
+                        if (!r) {
+                          if (k.throwDeprecation) throw new Error(t);
+                          k.traceDeprecation ? console.trace(t) : console.error(t), (r = !0);
+                        }
+                        return e.apply(this, arguments);
+                      };
+                    }),
+                    {});
+                function c(e, t) {
+                  var r = { seen: [], stylize: i };
+                  return (
+                    3 <= arguments.length && (r.depth = arguments[2]),
+                    4 <= arguments.length && (r.colors = arguments[3]),
+                    h(t) ? (r.showHidden = t) : t && S._extend(r, t),
+                    g(r.showHidden) && (r.showHidden = !1),
+                    g(r.depth) && (r.depth = 2),
+                    g(r.colors) && (r.colors = !1),
+                    g(r.customInspect) && (r.customInspect = !0),
+                    r.colors && (r.stylize = s),
+                    u(r, e, r.depth)
+                  );
+                }
+                function s(e, t) {
+                  t = c.styles[t];
+                  return t ? '\x1b[' + c.colors[t][0] + 'm' + e + '\x1b[' + c.colors[t][1] + 'm' : e;
+                }
+                function i(e, t) {
+                  return e;
+                }
+                function u(t, r, n) {
+                  if (
+                    t.customInspect &&
+                    r &&
+                    x(r.inspect) &&
+                    r.inspect !== S.inspect &&
+                    (!r.constructor || r.constructor.prototype !== r)
+                  )
+                    return b((e = r.inspect(n, t))) ? e : u(t, e, n);
+                  var e = (function (e, t) {
+                    if (g(t)) return e.stylize('undefined', 'undefined');
+                    {
+                      var r;
+                      if (b(t))
+                        return (
+                          (r =
+                            "'" +
+                            JSON.stringify(t).replace(/^"|"$/g, '').replace(/'/g, "\\'").replace(/\\"/g, '"') +
+                            "'"),
+                          e.stylize(r, 'string')
+                        );
+                    }
+                    return y(t)
+                      ? e.stylize('' + t, 'number')
+                      : h(t)
+                      ? e.stylize('' + t, 'boolean')
+                      : m(t)
+                      ? e.stylize('null', 'null')
+                      : void 0;
+                  })(t, r);
+                  if (e) return e;
+                  var s,
+                    e = Object.keys(r),
+                    i =
+                      ((s = {}),
+                      e.forEach(function (e, t) {
+                        s[e] = !0;
+                      }),
+                      s);
+                  if (
+                    (t.showHidden && (e = Object.getOwnPropertyNames(r)),
+                    w(r) && (0 <= e.indexOf('message') || 0 <= e.indexOf('description')))
+                  )
+                    return p(r);
+                  if (0 === e.length) {
+                    if (x(r)) return (o = r.name ? ': ' + r.name : ''), t.stylize('[Function' + o + ']', 'special');
+                    if (v(r)) return t.stylize(RegExp.prototype.toString.call(r), 'regexp');
+                    if (j(r)) return t.stylize(Date.prototype.toString.call(r), 'date');
+                    if (w(r)) return p(r);
+                  }
+                  var o = '',
+                    a = !1,
+                    c = ['{', '}'];
+                  if (
+                    (d(r) && ((a = !0), (c = ['[', ']'])),
+                    x(r) && (o = ' [Function' + (r.name ? ': ' + r.name : '') + ']'),
+                    v(r) && (o = ' ' + RegExp.prototype.toString.call(r)),
+                    j(r) && (o = ' ' + Date.prototype.toUTCString.call(r)),
+                    w(r) && (o = ' ' + p(r)),
+                    0 === e.length && (!a || 0 == r.length))
+                  )
+                    return c[0] + o + c[1];
+                  if (n < 0)
+                    return v(r)
+                      ? t.stylize(RegExp.prototype.toString.call(r), 'regexp')
+                      : t.stylize('[Object]', 'special');
+                  t.seen.push(r),
+                    (l = a
+                      ? (function (t, r, n, s, e) {
+                          for (var i = [], o = 0, a = r.length; o < a; ++o)
+                            T(r, String(o)) ? i.push(f(t, r, n, s, String(o), !0)) : i.push('');
+                          return (
+                            e.forEach(function (e) {
+                              e.match(/^\d+$/) || i.push(f(t, r, n, s, e, !0));
+                            }),
+                            i
+                          );
+                        })(t, r, n, i, e)
+                      : e.map(function (e) {
+                          return f(t, r, n, i, e, a);
+                        })),
+                    t.seen.pop();
+                  var l;
+                  return 60 <
+                    l.reduce(function (e, t) {
+                      return 0 <= t.indexOf('\n') && 0, e + t.replace(/\u001b\[\d\d?m/g, '').length + 1;
+                    }, 0)
+                    ? c[0] + ('' === o ? '' : o + '\n ') + ' ' + l.join(',\n  ') + ' ' + c[1]
+                    : c[0] + o + ' ' + l.join(', ') + ' ' + c[1];
+                }
+                function p(e) {
+                  return '[' + Error.prototype.toString.call(e) + ']';
+                }
+                function f(e, t, r, n, s, i) {
+                  var o,
+                    a,
+                    t = Object.getOwnPropertyDescriptor(t, s) || { value: t[s] };
+                  if (
+                    (t.get
+                      ? (a = t.set ? e.stylize('[Getter/Setter]', 'special') : e.stylize('[Getter]', 'special'))
+                      : t.set && (a = e.stylize('[Setter]', 'special')),
+                    T(n, s) || (o = '[' + s + ']'),
+                    a ||
+                      (e.seen.indexOf(t.value) < 0
+                        ? -1 < (a = m(r) ? u(e, t.value, null) : u(e, t.value, r - 1)).indexOf('\n') &&
+                          (a = i
+                            ? a
+                                .split('\n')
+                                .map(function (e) {
+                                  return '  ' + e;
+                                })
+                                .join('\n')
+                                .substr(2)
+                            : '\n' +
+                              a
+                                .split('\n')
+                                .map(function (e) {
+                                  return '   ' + e;
+                                })
+                                .join('\n'))
+                        : (a = e.stylize('[Circular]', 'special'))),
+                    g(o))
+                  ) {
+                    if (i && s.match(/^\d+$/)) return a;
+                    o = (o = JSON.stringify('' + s)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)
+                      ? ((o = o.substr(1, o.length - 2)), e.stylize(o, 'name'))
+                      : ((o = o
+                          .replace(/'/g, "\\'")
+                          .replace(/\\"/g, '"')
+                          .replace(/(^"|"$)/g, "'")),
+                        e.stylize(o, 'string'));
+                  }
+                  return o + ': ' + a;
+                }
+                function d(e) {
+                  return Array.isArray(e);
+                }
+                function h(e) {
+                  return 'boolean' == typeof e;
+                }
+                function m(e) {
+                  return null === e;
+                }
+                function y(e) {
+                  return 'number' == typeof e;
+                }
+                function b(e) {
+                  return 'string' == typeof e;
+                }
+                function g(e) {
+                  return void 0 === e;
+                }
+                function v(e) {
+                  return l(e) && '[object RegExp]' === t(e);
+                }
+                function l(e) {
+                  return 'object' == typeof e && null !== e;
+                }
+                function j(e) {
+                  return l(e) && '[object Date]' === t(e);
+                }
+                function w(e) {
+                  return l(e) && ('[object Error]' === t(e) || e instanceof Error);
+                }
+                function x(e) {
+                  return 'function' == typeof e;
+                }
+                function t(e) {
+                  return Object.prototype.toString.call(e);
+                }
+                function r(e) {
+                  return e < 10 ? '0' + e.toString(10) : e.toString(10);
+                }
+                (S.debuglog = function (t) {
+                  var r;
+                  return (
+                    g(e) && (e = k.env.NODE_DEBUG || ''),
+                    (t = t.toUpperCase()),
+                    n[t] ||
+                      (new RegExp('\\b' + t + '\\b', 'i').test(e)
+                        ? ((r = k.pid),
+                          (n[t] = function () {
+                            var e = S.format.apply(S, arguments);
+                            console.error('%s %d: %s', t, r, e);
+                          }))
+                        : (n[t] = function () {})),
+                    n[t]
+                  );
+                }),
+                  ((S.inspect = c).colors = {
+                    bold: [1, 22],
+                    italic: [3, 23],
+                    underline: [4, 24],
+                    inverse: [7, 27],
+                    white: [37, 39],
+                    grey: [90, 39],
+                    black: [30, 39],
+                    blue: [34, 39],
+                    cyan: [36, 39],
+                    green: [32, 39],
+                    magenta: [35, 39],
+                    red: [31, 39],
+                    yellow: [33, 39]
+                  }),
+                  (c.styles = {
+                    special: 'cyan',
+                    number: 'yellow',
+                    boolean: 'yellow',
+                    undefined: 'grey',
+                    null: 'bold',
+                    string: 'green',
+                    date: 'magenta',
+                    regexp: 'red'
+                  }),
+                  (S.isArray = d),
+                  (S.isBoolean = h),
+                  (S.isNull = m),
+                  (S.isNullOrUndefined = function (e) {
+                    return null == e;
+                  }),
+                  (S.isNumber = y),
+                  (S.isString = b),
+                  (S.isSymbol = function (e) {
+                    return 'symbol' == typeof e;
+                  }),
+                  (S.isUndefined = g),
+                  (S.isRegExp = v),
+                  (S.isObject = l),
+                  (S.isDate = j),
+                  (S.isError = w),
+                  (S.isFunction = x),
+                  (S.isPrimitive = function (e) {
+                    return (
+                      null === e ||
+                      'boolean' == typeof e ||
+                      'number' == typeof e ||
+                      'string' == typeof e ||
+                      'symbol' == typeof e ||
+                      void 0 === e
+                    );
+                  }),
+                  (S.isBuffer = _('./support/isBuffer'));
+                var o = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+                function T(e, t) {
+                  return Object.prototype.hasOwnProperty.call(e, t);
+                }
+                (S.log = function () {
+                  var e, t;
+                  console.log(
+                    '%s - %s',
+                    ((e = new Date()),
+                    (t = [r(e.getHours()), r(e.getMinutes()), r(e.getSeconds())].join(':')),
+                    [e.getDate(), o[e.getMonth()], t].join(' ')),
+                    S.format.apply(S, arguments)
+                  );
+                }),
+                  (S.inherits = _('inherits')),
+                  (S._extend = function (e, t) {
+                    if (!t || !l(t)) return e;
+                    for (var r = Object.keys(t), n = r.length; n--; ) e[r[n]] = t[r[n]];
+                    return e;
+                  });
+              }.call(this);
+            }.call(
+              this,
+              _('_process'),
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          { './support/isBuffer': 83, _process: 441, inherits: 82 }
+        ],
+        85: [
+          function (e, t, r) {
+            'use strict';
+            (r.byteLength = function (e) {
+              var e = u(e),
+                t = e[0],
+                e = e[1];
+              return (3 * (t + e)) / 4 - e;
+            }),
+              (r.toByteArray = function (e) {
+                var t,
+                  r,
+                  n = u(e),
+                  s = n[0],
+                  n = n[1],
+                  i = new l(
+                    (function (e, t) {
+                      return (3 * (e + t)) / 4 - t;
+                    })(s, n)
+                  ),
+                  o = 0,
+                  a = 0 < n ? s - 4 : s;
+                for (r = 0; r < a; r += 4)
+                  (t =
+                    (c[e.charCodeAt(r)] << 18) |
+                    (c[e.charCodeAt(r + 1)] << 12) |
+                    (c[e.charCodeAt(r + 2)] << 6) |
+                    c[e.charCodeAt(r + 3)]),
+                    (i[o++] = (t >> 16) & 255),
+                    (i[o++] = (t >> 8) & 255),
+                    (i[o++] = 255 & t);
+                2 === n && ((t = (c[e.charCodeAt(r)] << 2) | (c[e.charCodeAt(r + 1)] >> 4)), (i[o++] = 255 & t));
+                1 === n &&
+                  ((t = (c[e.charCodeAt(r)] << 10) | (c[e.charCodeAt(r + 1)] << 4) | (c[e.charCodeAt(r + 2)] >> 2)),
+                  (i[o++] = (t >> 8) & 255),
+                  (i[o++] = 255 & t));
+                return i;
+              }),
+              (r.fromByteArray = function (e) {
+                for (var t, r = e.length, n = r % 3, s = [], i = 0, o = r - n; i < o; i += 16383)
+                  s.push(
+                    (function (e, t, r) {
+                      for (var n, s = [], i = t; i < r; i += 3)
+                        (n = ((e[i] << 16) & 16711680) + ((e[i + 1] << 8) & 65280) + (255 & e[i + 2])),
+                          s.push(
+                            (function (e) {
+                              return a[(e >> 18) & 63] + a[(e >> 12) & 63] + a[(e >> 6) & 63] + a[63 & e];
+                            })(n)
+                          );
+                      return s.join('');
+                    })(e, i, o < i + 16383 ? o : i + 16383)
+                  );
+                1 == n
+                  ? ((t = e[r - 1]), s.push(a[t >> 2] + a[(t << 4) & 63] + '=='))
+                  : 2 == n &&
+                    ((t = (e[r - 2] << 8) + e[r - 1]), s.push(a[t >> 10] + a[(t >> 4) & 63] + a[(t << 2) & 63] + '='));
+                return s.join('');
+              });
+            for (
+              var a = [],
+                c = [],
+                l = 'undefined' != typeof Uint8Array ? Uint8Array : Array,
+                n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
+                s = 0,
+                i = n.length;
+              s < i;
+              ++s
+            )
+              (a[s] = n[s]), (c[n.charCodeAt(s)] = s);
+            function u(e) {
+              var t = e.length;
+              if (0 < t % 4) throw new Error('Invalid string. Length must be a multiple of 4');
+              (e = e.indexOf('=')), (t = (e = -1 === e ? t : e) === t ? 0 : 4 - (e % 4));
+              return [e, t];
+            }
+            (c['-'.charCodeAt(0)] = 62), (c['_'.charCodeAt(0)] = 63);
+          },
+          {}
+        ],
+        86: [
+          function (e, t, r) {
+            var n, s;
+            (n = this),
+              (s = function () {
+                function o(t) {
+                  function e(e) {
+                    e = t.match(e);
+                    return (e && 1 < e.length && e[1]) || '';
+                  }
+                  function r(e) {
+                    e = t.match(e);
+                    return (e && 1 < e.length && e[2]) || '';
+                  }
+                  var n,
+                    s = e(/(ipod|iphone|ipad)/i).toLowerCase(),
+                    i = !/like android/i.test(t) && /android/i.test(t),
+                    o = /nexus\s*[0-6]\s*/i.test(t),
+                    a = !o && /nexus\s*[0-9]+/i.test(t),
+                    c = /CrOS/.test(t),
+                    l = /silk/i.test(t),
+                    u = /sailfish/i.test(t),
+                    p = /tizen/i.test(t),
+                    f = /(web|hpw)(o|0)s/i.test(t),
+                    d = /windows phone/i.test(t),
+                    h = (/SamsungBrowser/i.test(t), !d && /windows/i.test(t)),
+                    m = !s && !l && /macintosh/i.test(t),
+                    y = !i && !u && !p && !f && /linux/i.test(t),
+                    b = r(/edg([ea]|ios)\/(\d+(\.\d+)?)/i),
+                    g = e(/version\/(\d+(\.\d+)?)/i),
+                    v = /tablet/i.test(t) && !/tablet pc/i.test(t),
+                    j = !v && /[^-]mobi/i.test(t),
+                    w = /xbox/i.test(t);
+                  /opera/i.test(t)
+                    ? (n = { name: 'Opera', opera: !0, version: g || e(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) })
+                    : /opr\/|opios/i.test(t)
+                    ? (n = { name: 'Opera', opera: !0, version: e(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i) || g })
+                    : /SamsungBrowser/i.test(t)
+                    ? (n = {
+                        name: 'Samsung Internet for Android',
+                        samsungBrowser: !0,
+                        version: g || e(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i)
+                      })
+                    : /Whale/i.test(t)
+                    ? (n = { name: 'NAVER Whale browser', whale: !0, version: e(/(?:whale)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /MZBrowser/i.test(t)
+                    ? (n = { name: 'MZ Browser', mzbrowser: !0, version: e(/(?:MZBrowser)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /coast/i.test(t)
+                    ? (n = { name: 'Opera Coast', coast: !0, version: g || e(/(?:coast)[\s\/](\d+(\.\d+)?)/i) })
+                    : /focus/i.test(t)
+                    ? (n = { name: 'Focus', focus: !0, version: e(/(?:focus)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /yabrowser/i.test(t)
+                    ? (n = {
+                        name: 'Yandex Browser',
+                        yandexbrowser: !0,
+                        version: g || e(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)
+                      })
+                    : /ucbrowser/i.test(t)
+                    ? (n = { name: 'UC Browser', ucbrowser: !0, version: e(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /mxios/i.test(t)
+                    ? (n = { name: 'Maxthon', maxthon: !0, version: e(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /epiphany/i.test(t)
+                    ? (n = { name: 'Epiphany', epiphany: !0, version: e(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /puffin/i.test(t)
+                    ? (n = { name: 'Puffin', puffin: !0, version: e(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) })
+                    : /sleipnir/i.test(t)
+                    ? (n = { name: 'Sleipnir', sleipnir: !0, version: e(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : /k-meleon/i.test(t)
+                    ? (n = { name: 'K-Meleon', kMeleon: !0, version: e(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) })
+                    : d
+                    ? ((n = { name: 'Windows Phone', osname: 'Windows Phone', windowsphone: !0 }),
+                      b
+                        ? ((n.msedge = !0), (n.version = b))
+                        : ((n.msie = !0), (n.version = e(/iemobile\/(\d+(\.\d+)?)/i))))
+                    : /msie|trident/i.test(t)
+                    ? (n = { name: 'Internet Explorer', msie: !0, version: e(/(?:msie |rv:)(\d+(\.\d+)?)/i) })
+                    : c
+                    ? (n = {
+                        name: 'Chrome',
+                        osname: 'Chrome OS',
+                        chromeos: !0,
+                        chromeBook: !0,
+                        chrome: !0,
+                        version: e(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
+                      })
+                    : /edg([ea]|ios)/i.test(t)
+                    ? (n = { name: 'Microsoft Edge', msedge: !0, version: b })
+                    : /vivaldi/i.test(t)
+                    ? (n = { name: 'Vivaldi', vivaldi: !0, version: e(/vivaldi\/(\d+(\.\d+)?)/i) || g })
+                    : u
+                    ? (n = {
+                        name: 'Sailfish',
+                        osname: 'Sailfish OS',
+                        sailfish: !0,
+                        version: e(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
+                      })
+                    : /seamonkey\//i.test(t)
+                    ? (n = { name: 'SeaMonkey', seamonkey: !0, version: e(/seamonkey\/(\d+(\.\d+)?)/i) })
+                    : /firefox|iceweasel|fxios/i.test(t)
+                    ? ((n = {
+                        name: 'Firefox',
+                        firefox: !0,
+                        version: e(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i)
+                      }),
+                      /\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(t) &&
+                        ((n.firefoxos = !0), (n.osname = 'Firefox OS')))
+                    : l
+                    ? (n = { name: 'Amazon Silk', silk: !0, version: e(/silk\/(\d+(\.\d+)?)/i) })
+                    : /phantom/i.test(t)
+                    ? (n = { name: 'PhantomJS', phantom: !0, version: e(/phantomjs\/(\d+(\.\d+)?)/i) })
+                    : /slimerjs/i.test(t)
+                    ? (n = { name: 'SlimerJS', slimer: !0, version: e(/slimerjs\/(\d+(\.\d+)?)/i) })
+                    : /blackberry|\bbb\d+/i.test(t) || /rim\stablet/i.test(t)
+                    ? (n = {
+                        name: 'BlackBerry',
+                        osname: 'BlackBerry OS',
+                        blackberry: !0,
+                        version: g || e(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
+                      })
+                    : f
+                    ? ((n = {
+                        name: 'WebOS',
+                        osname: 'WebOS',
+                        webos: !0,
+                        version: g || e(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
+                      }),
+                      /touchpad\//i.test(t) && (n.touchpad = !0))
+                    : /bada/i.test(t)
+                    ? (n = { name: 'Bada', osname: 'Bada', bada: !0, version: e(/dolfin\/(\d+(\.\d+)?)/i) })
+                    : p
+                    ? (n = {
+                        name: 'Tizen',
+                        osname: 'Tizen',
+                        tizen: !0,
+                        version: e(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || g
+                      })
+                    : /qupzilla/i.test(t)
+                    ? (n = { name: 'QupZilla', qupzilla: !0, version: e(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || g })
+                    : /chromium/i.test(t)
+                    ? (n = { name: 'Chromium', chromium: !0, version: e(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || g })
+                    : /chrome|crios|crmo/i.test(t)
+                    ? (n = { name: 'Chrome', chrome: !0, version: e(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) })
+                    : i
+                    ? (n = { name: 'Android', version: g })
+                    : /safari|applewebkit/i.test(t)
+                    ? ((n = { name: 'Safari', safari: !0 }), g && (n.version = g))
+                    : s
+                    ? ((n = { name: 'iphone' == s ? 'iPhone' : 'ipad' == s ? 'iPad' : 'iPod' }), g && (n.version = g))
+                    : (n = /googlebot/i.test(t)
+                        ? { name: 'Googlebot', googlebot: !0, version: e(/googlebot\/(\d+(\.\d+))/i) || g }
+                        : { name: e(/^(.*)\/(.*) /), version: r(/^(.*)\/(.*) /) }),
+                    !n.msedge && /(apple)?webkit/i.test(t)
+                      ? (/(apple)?webkit\/537\.36/i.test(t)
+                          ? ((n.name = n.name || 'Blink'), (n.blink = !0))
+                          : ((n.name = n.name || 'Webkit'), (n.webkit = !0)),
+                        !n.version && g && (n.version = g))
+                      : !n.opera &&
+                        /gecko\//i.test(t) &&
+                        ((n.name = n.name || 'Gecko'),
+                        (n.gecko = !0),
+                        (n.version = n.version || e(/gecko\/(\d+(\.\d+)?)/i))),
+                    n.windowsphone || (!i && !n.silk)
+                      ? !n.windowsphone && s
+                        ? ((n[s] = !0), (n.ios = !0), (n.osname = 'iOS'))
+                        : m
+                        ? ((n.mac = !0), (n.osname = 'macOS'))
+                        : w
+                        ? ((n.xbox = !0), (n.osname = 'Xbox'))
+                        : h
+                        ? ((n.windows = !0), (n.osname = 'Windows'))
+                        : y && ((n.linux = !0), (n.osname = 'Linux'))
+                      : ((n.android = !0), (n.osname = 'Android'));
+                  (d = ''),
+                    n.windows
+                      ? (d = (function (e) {
+                          switch (e) {
+                            case 'NT':
+                              return 'NT';
+                            case 'XP':
+                              return 'XP';
+                            case 'NT 5.0':
+                              return '2000';
+                            case 'NT 5.1':
+                              return 'XP';
+                            case 'NT 5.2':
+                              return '2003';
+                            case 'NT 6.0':
+                              return 'Vista';
+                            case 'NT 6.1':
+                              return '7';
+                            case 'NT 6.2':
+                              return '8';
+                            case 'NT 6.3':
+                              return '8.1';
+                            case 'NT 10.0':
+                              return '10';
+                            default:
+                              return;
+                          }
+                        })(e(/Windows ((NT|XP)( \d\d?.\d)?)/i)))
+                      : n.windowsphone
+                      ? (d = e(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i))
+                      : n.mac
+                      ? (d = (d = e(/Mac OS X (\d+([_\.\s]\d+)*)/i)).replace(/[_\s]/g, '.'))
+                      : s
+                      ? (d = (d = e(/os (\d+([_\s]\d+)*) like mac os x/i)).replace(/[_\s]/g, '.'))
+                      : i
+                      ? (d = e(/android[ \/-](\d+(\.\d+)*)/i))
+                      : n.webos
+                      ? (d = e(/(?:web|hpw)os\/(\d+(\.\d+)*)/i))
+                      : n.blackberry
+                      ? (d = e(/rim\stablet\sos\s(\d+(\.\d+)*)/i))
+                      : n.bada
+                      ? (d = e(/bada\/(\d+(\.\d+)*)/i))
+                      : n.tizen && (d = e(/tizen[\/\s](\d+(\.\d+)*)/i)),
+                    d && (n.osversion = d),
+                    (c = !n.windows && d.split('.')[0]);
+                  return (
+                    v || a || 'ipad' == s || (i && (3 == c || (4 <= c && !j))) || n.silk
+                      ? (n.tablet = !0)
+                      : (j || 'iphone' == s || 'ipod' == s || i || o || n.blackberry || n.webos || n.bada) &&
+                        (n.mobile = !0),
+                    n.msedge ||
+                    (n.msie && 10 <= n.version) ||
+                    (n.yandexbrowser && 15 <= n.version) ||
+                    (n.vivaldi && 1 <= n.version) ||
+                    (n.chrome && 20 <= n.version) ||
+                    (n.samsungBrowser && 4 <= n.version) ||
+                    (n.whale && 1 === x([n.version, '1.0'])) ||
+                    (n.mzbrowser && 1 === x([n.version, '6.0'])) ||
+                    (n.focus && 1 === x([n.version, '1.0'])) ||
+                    (n.firefox && 20 <= n.version) ||
+                    (n.safari && 6 <= n.version) ||
+                    (n.opera && 10 <= n.version) ||
+                    (n.ios && n.osversion && 6 <= n.osversion.split('.')[0]) ||
+                    (n.blackberry && 10.1 <= n.version) ||
+                    (n.chromium && 20 <= n.version)
+                      ? (n.a = !0)
+                      : (n.msie && n.version < 10) ||
+                        (n.chrome && n.version < 20) ||
+                        (n.firefox && n.version < 20) ||
+                        (n.safari && n.version < 6) ||
+                        (n.opera && n.version < 10) ||
+                        (n.ios && n.osversion && n.osversion.split('.')[0] < 6) ||
+                        (n.chromium && n.version < 20)
+                      ? (n.c = !0)
+                      : (n.x = !0),
+                    n
+                  );
+                }
+                var a = o(('undefined' != typeof navigator && navigator.userAgent) || '');
+                function n(e) {
+                  return e.split('.').length;
+                }
+                function s(e, t) {
+                  var r,
+                    n = [];
+                  if (Array.prototype.map) return Array.prototype.map.call(e, t);
+                  for (r = 0; r < e.length; r++) n.push(t(e[r]));
+                  return n;
+                }
+                function x(e) {
+                  for (
+                    var r = Math.max(n(e[0]), n(e[1])),
+                      t = s(e, function (e) {
+                        var t = r - n(e);
+                        return s((e += new Array(1 + t).join('.0')).split('.'), function (e) {
+                          return new Array(20 - e.length).join('0') + e;
+                        }).reverse();
+                      });
+                    0 <= --r;
+
+                  ) {
+                    if (t[0][r] > t[1][r]) return 1;
+                    if (t[0][r] !== t[1][r]) return -1;
+                    if (0 === r) return 0;
+                  }
+                }
+                function i(e, t, r) {
+                  var n,
+                    s = a,
+                    i =
+                      ('string' == typeof t && ((r = t), (t = void 0)),
+                      void 0 === t && (t = !1),
+                      '' + (s = r ? o(r) : s).version);
+                  for (n in e)
+                    if (e.hasOwnProperty(n) && s[n]) {
+                      if ('string' != typeof e[n])
+                        throw new Error(
+                          'Browser version in the minVersion map should be a string: ' + n + ': ' + String(e)
+                        );
+                      return x([i, e[n]]) < 0;
+                    }
+                  return t;
+                }
+                return (
+                  (a.test = function (e) {
+                    for (var t = 0; t < e.length; ++t) {
+                      var r = e[t];
+                      if ('string' == typeof r && r in a) return !0;
+                    }
+                    return !1;
+                  }),
+                  (a.isUnsupportedBrowser = i),
+                  (a.compareVersions = x),
+                  (a.check = function (e, t, r) {
+                    return !i(e, t, r);
+                  }),
+                  (a._detect = o),
+                  (a.detect = o),
+                  a
+                );
+              }),
+              void 0 !== t && t.exports ? (t.exports = s()) : (n.bowser = s());
+          },
+          {}
+        ],
+        87: [function (e, t, r) {}, {}],
+        88: [
+          function (e, t, r) {
+            var n = e('buffer').Buffer,
+              s =
+                n.isEncoding ||
+                function (e) {
+                  switch (e && e.toLowerCase()) {
+                    case 'hex':
+                    case 'utf8':
+                    case 'utf-8':
+                    case 'ascii':
+                    case 'binary':
+                    case 'base64':
+                    case 'ucs2':
+                    case 'ucs-2':
+                    case 'utf16le':
+                    case 'utf-16le':
+                    case 'raw':
+                      return !0;
+                    default:
+                      return !1;
+                  }
+                };
+            e = r.StringDecoder = function (e) {
+              this.encoding = (e || 'utf8').toLowerCase().replace(/[-_]/, '');
+              if (e && !s(e)) throw new Error('Unknown encoding: ' + e);
+              switch (this.encoding) {
+                case 'utf8':
+                  this.surrogateSize = 3;
+                  break;
+                case 'ucs2':
+                case 'utf16le':
+                  (this.surrogateSize = 2), (this.detectIncompleteChar = o);
+                  break;
+                case 'base64':
+                  (this.surrogateSize = 3), (this.detectIncompleteChar = a);
+                  break;
+                default:
+                  return void (this.write = i);
+              }
+              (this.charBuffer = new n(6)), (this.charReceived = 0), (this.charLength = 0);
+            };
+            function i(e) {
+              return e.toString(this.encoding);
+            }
+            function o(e) {
+              (this.charReceived = e.length % 2), (this.charLength = this.charReceived ? 2 : 0);
+            }
+            function a(e) {
+              (this.charReceived = e.length % 3), (this.charLength = this.charReceived ? 3 : 0);
+            }
+            (e.prototype.write = function (e) {
+              for (var t = ''; this.charLength; ) {
+                var r =
+                  e.length >= this.charLength - this.charReceived ? this.charLength - this.charReceived : e.length;
+                if (
+                  (e.copy(this.charBuffer, this.charReceived, 0, r),
+                  (this.charReceived += r),
+                  this.charReceived < this.charLength)
+                )
+                  return '';
+                if (
+                  ((e = e.slice(r, e.length)),
+                  !(
+                    55296 <=
+                      (n = (t = this.charBuffer.slice(0, this.charLength).toString(this.encoding)).charCodeAt(
+                        t.length - 1
+                      )) && n <= 56319
+                  ))
+                ) {
+                  if ((this.charReceived = this.charLength = 0) === e.length) return t;
+                  break;
+                }
+                (this.charLength += this.surrogateSize), (t = '');
+              }
+              this.detectIncompleteChar(e);
+              var n,
+                s,
+                i = e.length,
+                i =
+                  (this.charLength &&
+                    (e.copy(this.charBuffer, 0, e.length - this.charReceived, i), (i -= this.charReceived)),
+                  (t += e.toString(this.encoding, 0, i)).length - 1);
+              return 55296 <= (n = t.charCodeAt(i)) && n <= 56319
+                ? ((s = this.surrogateSize),
+                  (this.charLength += s),
+                  (this.charReceived += s),
+                  this.charBuffer.copy(this.charBuffer, s, 0, s),
+                  e.copy(this.charBuffer, 0, 0, s),
+                  t.substring(0, i))
+                : t;
+            }),
+              (e.prototype.detectIncompleteChar = function (e) {
+                for (var t = 3 <= e.length ? 3 : e.length; 0 < t; t--) {
+                  var r = e[e.length - t];
+                  if (1 == t && r >> 5 == 6) {
+                    this.charLength = 2;
+                    break;
+                  }
+                  if (t <= 2 && r >> 4 == 14) {
+                    this.charLength = 3;
+                    break;
+                  }
+                  if (t <= 3 && r >> 3 == 30) {
+                    this.charLength = 4;
+                    break;
+                  }
+                }
+                this.charReceived = t;
+              }),
+              (e.prototype.end = function (e) {
+                var t,
+                  r,
+                  n = '';
+                return (
+                  e && e.length && (n = this.write(e)),
+                  this.charReceived &&
+                    ((e = this.charReceived),
+                    (t = this.charBuffer),
+                    (r = this.encoding),
+                    (n += t.slice(0, e).toString(r))),
+                  n
+                );
+              });
+          },
+          { buffer: 89 }
+        ],
+        89: [
+          function (C, e, N) {
+            !function (e, t) {
+              !function () {
+                'use strict';
+                var k = C('base64-js'),
+                  i = C('ieee754'),
+                  a = C('isarray');
+                function r() {
+                  return p.TYPED_ARRAY_SUPPORT ? 2147483647 : 1073741823;
+                }
+                function c(e, t) {
+                  if (r() < t) throw new RangeError('Invalid typed array length');
+                  return (
+                    p.TYPED_ARRAY_SUPPORT
+                      ? ((e = new Uint8Array(t)).__proto__ = p.prototype)
+                      : ((e = null === e ? new p(t) : e).length = t),
+                    e
+                  );
+                }
+                function p(e, t, r) {
+                  if (!(p.TYPED_ARRAY_SUPPORT || this instanceof p)) return new p(e, t, r);
+                  if ('number' != typeof e) return n(this, e, t, r);
+                  if ('string' == typeof t)
+                    throw new Error('If encoding is specified then the first argument must be a string');
+                  return o(this, e);
+                }
+                function n(e, t, r, n) {
+                  if ('number' == typeof t) throw new TypeError('"value" argument must not be a number');
+                  if ('undefined' != typeof ArrayBuffer && t instanceof ArrayBuffer) {
+                    var s = e,
+                      i = t,
+                      o = r;
+                    if ((i.byteLength, o < 0 || i.byteLength < o)) throw new RangeError("'offset' is out of bounds");
+                    if (i.byteLength < o + (n || 0)) throw new RangeError("'length' is out of bounds");
+                    return (
+                      (i =
+                        void 0 === o && void 0 === n
+                          ? new Uint8Array(i)
+                          : void 0 === n
+                          ? new Uint8Array(i, o)
+                          : new Uint8Array(i, o, n)),
+                      p.TYPED_ARRAY_SUPPORT ? ((s = i).__proto__ = p.prototype) : (s = l(s, i)),
+                      s
+                    );
+                  }
+                  if ('string' != typeof t) {
+                    (o = e), (n = t);
+                    if (p.isBuffer(n))
+                      return (i = 0 | u(n.length)), 0 === (o = c(o, i)).length || n.copy(o, 0, 0, i), o;
+                    if (n) {
+                      if (('undefined' != typeof ArrayBuffer && n.buffer instanceof ArrayBuffer) || 'length' in n)
+                        return 'number' != typeof n.length ||
+                          (function (e) {
+                            return e != e;
+                          })(n.length)
+                          ? c(o, 0)
+                          : l(o, n);
+                      if ('Buffer' === n.type && a(n.data)) return l(o, n.data);
+                    }
+                    throw new TypeError(
+                      'First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.'
+                    );
+                  }
+                  (s = e), (n = t), (e = r);
+                  if (!p.isEncoding((e = 'string' == typeof e && '' !== e ? e : 'utf8')))
+                    throw new TypeError('"encoding" must be a valid string encoding');
+                  t = 0 | f(n, e);
+                  return (s = (n = (s = c(s, t)).write(n, e)) !== t ? s.slice(0, n) : s);
+                }
+                function s(e) {
+                  if ('number' != typeof e) throw new TypeError('"size" argument must be a number');
+                  if (e < 0) throw new RangeError('"size" argument must not be negative');
+                }
+                function o(e, t) {
+                  if ((s(t), (e = c(e, t < 0 ? 0 : 0 | u(t))), !p.TYPED_ARRAY_SUPPORT))
+                    for (var r = 0; r < t; ++r) e[r] = 0;
+                  return e;
+                }
+                function l(e, t) {
+                  var r = t.length < 0 ? 0 : 0 | u(t.length);
+                  e = c(e, r);
+                  for (var n = 0; n < r; n += 1) e[n] = 255 & t[n];
+                  return e;
+                }
+                function u(e) {
+                  if (e >= r())
+                    throw new RangeError(
+                      'Attempt to allocate Buffer larger than maximum size: 0x' + r().toString(16) + ' bytes'
+                    );
+                  return 0 | e;
+                }
+                function f(e, t) {
+                  if (p.isBuffer(e)) return e.length;
+                  if (
+                    'undefined' != typeof ArrayBuffer &&
+                    'function' == typeof ArrayBuffer.isView &&
+                    (ArrayBuffer.isView(e) || e instanceof ArrayBuffer)
+                  )
+                    return e.byteLength;
+                  var r = (e = 'string' != typeof e ? '' + e : e).length;
+                  if (0 === r) return 0;
+                  for (var n = !1; ; )
+                    switch (t) {
+                      case 'ascii':
+                      case 'latin1':
+                      case 'binary':
+                        return r;
+                      case 'utf8':
+                      case 'utf-8':
+                      case void 0:
+                        return A(e).length;
+                      case 'ucs2':
+                      case 'ucs-2':
+                      case 'utf16le':
+                      case 'utf-16le':
+                        return 2 * r;
+                      case 'hex':
+                        return r >>> 1;
+                      case 'base64':
+                        return D(e).length;
+                      default:
+                        if (n) return A(e).length;
+                        (t = ('' + t).toLowerCase()), (n = !0);
+                    }
+                }
+                function t(e, t, r) {
+                  var n,
+                    s = !1;
+                  if ((t = void 0 === t || t < 0 ? 0 : t) > this.length) return '';
+                  if ((r = void 0 === r || r > this.length ? this.length : r) <= 0) return '';
+                  if ((r >>>= 0) <= (t >>>= 0)) return '';
+                  for (e = e || 'utf8'; ; )
+                    switch (e) {
+                      case 'hex':
+                        var i = this,
+                          o = t,
+                          a = r,
+                          c = i.length;
+                        (!a || a < 0 || c < a) && (a = c);
+                        for (var l = '', u = (o = !o || o < 0 ? 0 : o); u < a; ++u)
+                          l += (function (e) {
+                            return e < 16 ? '0' + e.toString(16) : e.toString(16);
+                          })(i[u]);
+                        return l;
+                      case 'utf8':
+                      case 'utf-8':
+                        return E(this, t, r);
+                      case 'ascii':
+                        var p = this,
+                          c = t,
+                          f = r,
+                          d = '';
+                        f = Math.min(p.length, f);
+                        for (var h = c; h < f; ++h) d += String.fromCharCode(127 & p[h]);
+                        return d;
+                      case 'latin1':
+                      case 'binary':
+                        var m = this,
+                          o = t,
+                          y = r,
+                          b = '';
+                        y = Math.min(m.length, y);
+                        for (var g = o; g < y; ++g) b += String.fromCharCode(m[g]);
+                        return b;
+                      case 'base64':
+                        return (
+                          (v = this),
+                          (n = r),
+                          0 === (j = t) && n === v.length ? k.fromByteArray(v) : k.fromByteArray(v.slice(j, n))
+                        );
+                      case 'ucs2':
+                      case 'ucs-2':
+                      case 'utf16le':
+                      case 'utf-16le':
+                        for (var v = t, j = r, w = this.slice(v, j), x = '', T = 0; T < w.length; T += 2)
+                          x += String.fromCharCode(w[T] + 256 * w[T + 1]);
+                        return x;
+                      default:
+                        if (s) throw new TypeError('Unknown encoding: ' + e);
+                        (e = (e + '').toLowerCase()), (s = !0);
+                    }
+                }
+                function d(e, t, r) {
+                  var n = e[t];
+                  (e[t] = e[r]), (e[r] = n);
+                }
+                function h(e, t, r, n, s) {
+                  if (0 === e.length) return -1;
+                  if (
+                    ('string' == typeof r
+                      ? ((n = r), (r = 0))
+                      : 2147483647 < r
+                      ? (r = 2147483647)
+                      : r < -2147483648 && (r = -2147483648),
+                    (r = +r),
+                    (r = (r = isNaN(r) ? (s ? 0 : e.length - 1) : r) < 0 ? e.length + r : r) >= e.length)
+                  ) {
+                    if (s) return -1;
+                    r = e.length - 1;
+                  } else if (r < 0) {
+                    if (!s) return -1;
+                    r = 0;
+                  }
+                  if (('string' == typeof t && (t = p.from(t, n)), p.isBuffer(t)))
+                    return 0 === t.length ? -1 : m(e, t, r, n, s);
+                  if ('number' == typeof t)
+                    return (
+                      (t &= 255),
+                      p.TYPED_ARRAY_SUPPORT && 'function' == typeof Uint8Array.prototype.indexOf
+                        ? (s ? Uint8Array.prototype.indexOf : Uint8Array.prototype.lastIndexOf).call(e, t, r)
+                        : m(e, [t], r, n, s)
+                    );
+                  throw new TypeError('val must be string, number or Buffer');
+                }
+                function m(e, t, r, n, s) {
+                  var i = 1,
+                    o = e.length,
+                    a = t.length;
+                  if (
+                    void 0 !== n &&
+                    ('ucs2' === (n = String(n).toLowerCase()) || 'ucs-2' === n || 'utf16le' === n || 'utf-16le' === n)
+                  ) {
+                    if (e.length < 2 || t.length < 2) return -1;
+                    (o /= i = 2), (a /= 2), (r /= 2);
+                  }
+                  function c(e, t) {
+                    return 1 === i ? e[t] : e.readUInt16BE(t * i);
+                  }
+                  if (s)
+                    for (var l = -1, u = r; u < o; u++)
+                      if (c(e, u) === c(t, -1 === l ? 0 : u - l)) {
+                        if (u - (l = -1 === l ? u : l) + 1 === a) return l * i;
+                      } else -1 !== l && (u -= u - l), (l = -1);
+                  else
+                    for (u = r = o < r + a ? o - a : r; 0 <= u; u--) {
+                      for (var p = !0, f = 0; f < a; f++)
+                        if (c(e, u + f) !== c(t, f)) {
+                          p = !1;
+                          break;
+                        }
+                      if (p) return u;
+                    }
+                  return -1;
+                }
+                function y(e, t, r, n) {
+                  return I(
+                    (function (e) {
+                      for (var t = [], r = 0; r < e.length; ++r) t.push(255 & e.charCodeAt(r));
+                      return t;
+                    })(t),
+                    e,
+                    r,
+                    n
+                  );
+                }
+                function b(e, t, r, n) {
+                  return I(
+                    (function (e, t) {
+                      for (var r, n, s = [], i = 0; i < e.length && !((t -= 2) < 0); ++i)
+                        (n = e.charCodeAt(i)), (r = n >> 8), (n = n % 256), s.push(n), s.push(r);
+                      return s;
+                    })(t, e.length - r),
+                    e,
+                    r,
+                    n
+                  );
+                }
+                function E(e, t, r) {
+                  r = Math.min(e.length, r);
+                  for (var n = [], s = t; s < r; ) {
+                    var i,
+                      o,
+                      a,
+                      c,
+                      l = e[s],
+                      u = null,
+                      p = 239 < l ? 4 : 223 < l ? 3 : 191 < l ? 2 : 1;
+                    if (s + p <= r)
+                      switch (p) {
+                        case 1:
+                          l < 128 && (u = l);
+                          break;
+                        case 2:
+                          128 == (192 & (i = e[s + 1])) && 127 < (c = ((31 & l) << 6) | (63 & i)) && (u = c);
+                          break;
+                        case 3:
+                          (i = e[s + 1]),
+                            (o = e[s + 2]),
+                            128 == (192 & i) &&
+                              128 == (192 & o) &&
+                              2047 < (c = ((15 & l) << 12) | ((63 & i) << 6) | (63 & o)) &&
+                              (c < 55296 || 57343 < c) &&
+                              (u = c);
+                          break;
+                        case 4:
+                          (i = e[s + 1]),
+                            (o = e[s + 2]),
+                            (a = e[s + 3]),
+                            128 == (192 & i) &&
+                              128 == (192 & o) &&
+                              128 == (192 & a) &&
+                              65535 < (c = ((15 & l) << 18) | ((63 & i) << 12) | ((63 & o) << 6) | (63 & a)) &&
+                              c < 1114112 &&
+                              (u = c);
+                      }
+                    null === u
+                      ? ((u = 65533), (p = 1))
+                      : 65535 < u && ((u -= 65536), n.push(((u >>> 10) & 1023) | 55296), (u = 56320 | (1023 & u))),
+                      n.push(u),
+                      (s += p);
+                  }
+                  var f = n,
+                    d = f.length;
+                  if (d <= g) return String.fromCharCode.apply(String, f);
+                  for (var h = '', m = 0; m < d; ) h += String.fromCharCode.apply(String, f.slice(m, (m += g)));
+                  return h;
+                }
+                (N.Buffer = p),
+                  (N.SlowBuffer = function (e) {
+                    +e != e && (e = 0);
+                    return p.alloc(+e);
+                  }),
+                  (N.INSPECT_MAX_BYTES = 50),
+                  (p.TYPED_ARRAY_SUPPORT =
+                    void 0 !== e.TYPED_ARRAY_SUPPORT
+                      ? e.TYPED_ARRAY_SUPPORT
+                      : (function () {
+                          try {
+                            var e = new Uint8Array(1);
+                            return (
+                              (e.__proto__ = {
+                                __proto__: Uint8Array.prototype,
+                                foo: function () {
+                                  return 42;
+                                }
+                              }),
+                              42 === e.foo() && 'function' == typeof e.subarray && 0 === e.subarray(1, 1).byteLength
+                            );
+                          } catch (e) {
+                            return !1;
+                          }
+                        })()),
+                  (N.kMaxLength = r()),
+                  (p.poolSize = 8192),
+                  (p._augment = function (e) {
+                    return (e.__proto__ = p.prototype), e;
+                  }),
+                  (p.from = function (e, t, r) {
+                    return n(null, e, t, r);
+                  }),
+                  p.TYPED_ARRAY_SUPPORT &&
+                    ((p.prototype.__proto__ = Uint8Array.prototype),
+                    (p.__proto__ = Uint8Array),
+                    'undefined' != typeof Symbol &&
+                      Symbol.species &&
+                      p[Symbol.species] === p &&
+                      Object.defineProperty(p, Symbol.species, { value: null, configurable: !0 })),
+                  (p.alloc = function (e, t, r) {
+                    return (
+                      (n = null),
+                      (t = t),
+                      (r = r),
+                      s((e = e)),
+                      !(e <= 0) && void 0 !== t
+                        ? 'string' == typeof r
+                          ? c(n, e).fill(t, r)
+                          : c(n, e).fill(t)
+                        : c(n, e)
+                    );
+                    var n;
+                  }),
+                  (p.allocUnsafe = function (e) {
+                    return o(null, e);
+                  }),
+                  (p.allocUnsafeSlow = function (e) {
+                    return o(null, e);
+                  }),
+                  (p.isBuffer = function (e) {
+                    return !(null == e || !e._isBuffer);
+                  }),
+                  (p.compare = function (e, t) {
+                    if (!p.isBuffer(e) || !p.isBuffer(t)) throw new TypeError('Arguments must be Buffers');
+                    if (e === t) return 0;
+                    for (var r = e.length, n = t.length, s = 0, i = Math.min(r, n); s < i; ++s)
+                      if (e[s] !== t[s]) {
+                        (r = e[s]), (n = t[s]);
+                        break;
+                      }
+                    return r < n ? -1 : n < r ? 1 : 0;
+                  }),
+                  (p.isEncoding = function (e) {
+                    switch (String(e).toLowerCase()) {
+                      case 'hex':
+                      case 'utf8':
+                      case 'utf-8':
+                      case 'ascii':
+                      case 'latin1':
+                      case 'binary':
+                      case 'base64':
+                      case 'ucs2':
+                      case 'ucs-2':
+                      case 'utf16le':
+                      case 'utf-16le':
+                        return !0;
+                      default:
+                        return !1;
+                    }
+                  }),
+                  (p.concat = function (e, t) {
+                    if (!a(e)) throw new TypeError('"list" argument must be an Array of Buffers');
+                    if (0 === e.length) return p.alloc(0);
+                    if (void 0 === t) for (s = t = 0; s < e.length; ++s) t += e[s].length;
+                    for (var r = p.allocUnsafe(t), n = 0, s = 0; s < e.length; ++s) {
+                      var i = e[s];
+                      if (!p.isBuffer(i)) throw new TypeError('"list" argument must be an Array of Buffers');
+                      i.copy(r, n), (n += i.length);
+                    }
+                    return r;
+                  }),
+                  (p.byteLength = f),
+                  (p.prototype._isBuffer = !0),
+                  (p.prototype.swap16 = function () {
+                    var e = this.length;
+                    if (e % 2 != 0) throw new RangeError('Buffer size must be a multiple of 16-bits');
+                    for (var t = 0; t < e; t += 2) d(this, t, t + 1);
+                    return this;
+                  }),
+                  (p.prototype.swap32 = function () {
+                    var e = this.length;
+                    if (e % 4 != 0) throw new RangeError('Buffer size must be a multiple of 32-bits');
+                    for (var t = 0; t < e; t += 4) d(this, t, t + 3), d(this, t + 1, t + 2);
+                    return this;
+                  }),
+                  (p.prototype.swap64 = function () {
+                    var e = this.length;
+                    if (e % 8 != 0) throw new RangeError('Buffer size must be a multiple of 64-bits');
+                    for (var t = 0; t < e; t += 8)
+                      d(this, t, t + 7), d(this, t + 1, t + 6), d(this, t + 2, t + 5), d(this, t + 3, t + 4);
+                    return this;
+                  }),
+                  (p.prototype.toString = function () {
+                    var e = 0 | this.length;
+                    return 0 == e ? '' : 0 === arguments.length ? E(this, 0, e) : t.apply(this, arguments);
+                  }),
+                  (p.prototype.equals = function (e) {
+                    if (p.isBuffer(e)) return this === e || 0 === p.compare(this, e);
+                    throw new TypeError('Argument must be a Buffer');
+                  }),
+                  (p.prototype.inspect = function () {
+                    var e = '',
+                      t = N.INSPECT_MAX_BYTES;
+                    return (
+                      0 < this.length &&
+                        ((e = this.toString('hex', 0, t).match(/.{2}/g).join(' ')), this.length > t && (e += ' ... ')),
+                      '<Buffer ' + e + '>'
+                    );
+                  }),
+                  (p.prototype.compare = function (e, t, r, n, s) {
+                    if (!p.isBuffer(e)) throw new TypeError('Argument must be a Buffer');
+                    if (
+                      (void 0 === r && (r = e ? e.length : 0),
+                      void 0 === n && (n = 0),
+                      void 0 === s && (s = this.length),
+                      (t = void 0 === t ? 0 : t) < 0 || r > e.length || n < 0 || s > this.length)
+                    )
+                      throw new RangeError('out of range index');
+                    if (s <= n && r <= t) return 0;
+                    if (s <= n) return -1;
+                    if (r <= t) return 1;
+                    if (this === e) return 0;
+                    for (
+                      var i = (s >>>= 0) - (n >>>= 0),
+                        o = (r >>>= 0) - (t >>>= 0),
+                        a = Math.min(i, o),
+                        c = this.slice(n, s),
+                        l = e.slice(t, r),
+                        u = 0;
+                      u < a;
+                      ++u
+                    )
+                      if (c[u] !== l[u]) {
+                        (i = c[u]), (o = l[u]);
+                        break;
+                      }
+                    return i < o ? -1 : o < i ? 1 : 0;
+                  }),
+                  (p.prototype.includes = function (e, t, r) {
+                    return -1 !== this.indexOf(e, t, r);
+                  }),
+                  (p.prototype.indexOf = function (e, t, r) {
+                    return h(this, e, t, r, !0);
+                  }),
+                  (p.prototype.lastIndexOf = function (e, t, r) {
+                    return h(this, e, t, r, !1);
+                  }),
+                  (p.prototype.write = function (e, t, r, n) {
+                    if (void 0 === t) (n = 'utf8'), (r = this.length), (t = 0);
+                    else if (void 0 === r && 'string' == typeof t) (n = t), (r = this.length), (t = 0);
+                    else {
+                      if (!isFinite(t))
+                        throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');
+                      (t |= 0), isFinite(r) ? ((r |= 0), void 0 === n && (n = 'utf8')) : ((n = r), (r = void 0));
+                    }
+                    var s = this.length - t;
+                    if (((void 0 === r || s < r) && (r = s), (0 < e.length && (r < 0 || t < 0)) || t > this.length))
+                      throw new RangeError('Attempt to write outside buffer bounds');
+                    n = n || 'utf8';
+                    for (var i, o, a, c = !1; ; )
+                      switch (n) {
+                        case 'hex':
+                          var l = this,
+                            u = e,
+                            p = t,
+                            f = r,
+                            d = ((p = Number(p) || 0), l.length - p);
+                          if (((!f || d < (f = Number(f))) && (f = d), (d = u.length) % 2 != 0))
+                            throw new TypeError('Invalid hex string');
+                          d / 2 < f && (f = d / 2);
+                          for (var h = 0; h < f; ++h) {
+                            var m = parseInt(u.substr(2 * h, 2), 16);
+                            if (isNaN(m)) return h;
+                            l[p + h] = m;
+                          }
+                          return h;
+                        case 'utf8':
+                        case 'utf-8':
+                          return (d = t), (a = r), I(A(e, (o = this).length - d), o, d, a);
+                        case 'ascii':
+                          return y(this, e, t, r);
+                        case 'latin1':
+                        case 'binary':
+                          return y(this, e, t, r);
+                        case 'base64':
+                          return (o = this), (a = t), (i = r), I(D(e), o, a, i);
+                        case 'ucs2':
+                        case 'ucs-2':
+                        case 'utf16le':
+                        case 'utf-16le':
+                          return b(this, e, t, r);
+                        default:
+                          if (c) throw new TypeError('Unknown encoding: ' + n);
+                          (n = ('' + n).toLowerCase()), (c = !0);
+                      }
+                  }),
+                  (p.prototype.toJSON = function () {
+                    return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) };
+                  });
+                var g = 4096;
+                function v(e, t, r) {
+                  if (e % 1 != 0 || e < 0) throw new RangeError('offset is not uint');
+                  if (r < e + t) throw new RangeError('Trying to access beyond buffer length');
+                }
+                function j(e, t, r, n, s, i) {
+                  if (!p.isBuffer(e)) throw new TypeError('"buffer" argument must be a Buffer instance');
+                  if (s < t || t < i) throw new RangeError('"value" argument is out of bounds');
+                  if (r + n > e.length) throw new RangeError('Index out of range');
+                }
+                function w(e, t, r, n) {
+                  t < 0 && (t = 65535 + t + 1);
+                  for (var s = 0, i = Math.min(e.length - r, 2); s < i; ++s)
+                    e[r + s] = (t & (255 << (8 * (n ? s : 1 - s)))) >>> (8 * (n ? s : 1 - s));
+                }
+                function x(e, t, r, n) {
+                  t < 0 && (t = 4294967295 + t + 1);
+                  for (var s = 0, i = Math.min(e.length - r, 4); s < i; ++s)
+                    e[r + s] = (t >>> (8 * (n ? s : 3 - s))) & 255;
+                }
+                function T(e, t, r, n) {
+                  if (r + n > e.length) throw new RangeError('Index out of range');
+                  if (r < 0) throw new RangeError('Index out of range');
+                }
+                function _(e, t, r, n, s) {
+                  return s || T(e, 0, r, 4), i.write(e, t, r, n, 23, 4), r + 4;
+                }
+                function S(e, t, r, n, s) {
+                  return s || T(e, 0, r, 8), i.write(e, t, r, n, 52, 8), r + 8;
+                }
+                (p.prototype.slice = function (e, t) {
+                  var r = this.length;
+                  if (
+                    ((e = ~~e) < 0 ? (e += r) < 0 && (e = 0) : r < e && (e = r),
+                    (t = void 0 === t ? r : ~~t) < 0 ? (t += r) < 0 && (t = 0) : r < t && (t = r),
+                    t < e && (t = e),
+                    p.TYPED_ARRAY_SUPPORT)
+                  )
+                    (s = this.subarray(e, t)).__proto__ = p.prototype;
+                  else for (var n = t - e, s = new p(n, void 0), i = 0; i < n; ++i) s[i] = this[i + e];
+                  return s;
+                }),
+                  (p.prototype.readUIntLE = function (e, t, r) {
+                    (e |= 0), (t |= 0), r || v(e, t, this.length);
+                    for (var n = this[e], s = 1, i = 0; ++i < t && (s *= 256); ) n += this[e + i] * s;
+                    return n;
+                  }),
+                  (p.prototype.readUIntBE = function (e, t, r) {
+                    (e |= 0), (t |= 0), r || v(e, t, this.length);
+                    for (var n = this[e + --t], s = 1; 0 < t && (s *= 256); ) n += this[e + --t] * s;
+                    return n;
+                  }),
+                  (p.prototype.readUInt8 = function (e, t) {
+                    return t || v(e, 1, this.length), this[e];
+                  }),
+                  (p.prototype.readUInt16LE = function (e, t) {
+                    return t || v(e, 2, this.length), this[e] | (this[e + 1] << 8);
+                  }),
+                  (p.prototype.readUInt16BE = function (e, t) {
+                    return t || v(e, 2, this.length), (this[e] << 8) | this[e + 1];
+                  }),
+                  (p.prototype.readUInt32LE = function (e, t) {
+                    return (
+                      t || v(e, 4, this.length),
+                      (this[e] | (this[e + 1] << 8) | (this[e + 2] << 16)) + 16777216 * this[e + 3]
+                    );
+                  }),
+                  (p.prototype.readUInt32BE = function (e, t) {
+                    return (
+                      t || v(e, 4, this.length),
+                      16777216 * this[e] + ((this[e + 1] << 16) | (this[e + 2] << 8) | this[e + 3])
+                    );
+                  }),
+                  (p.prototype.readIntLE = function (e, t, r) {
+                    (e |= 0), (t |= 0), r || v(e, t, this.length);
+                    for (var n = this[e], s = 1, i = 0; ++i < t && (s *= 256); ) n += this[e + i] * s;
+                    return (s *= 128) <= n && (n -= Math.pow(2, 8 * t)), n;
+                  }),
+                  (p.prototype.readIntBE = function (e, t, r) {
+                    (e |= 0), (t |= 0), r || v(e, t, this.length);
+                    for (var n = t, s = 1, i = this[e + --n]; 0 < n && (s *= 256); ) i += this[e + --n] * s;
+                    return (s *= 128) <= i && (i -= Math.pow(2, 8 * t)), i;
+                  }),
+                  (p.prototype.readInt8 = function (e, t) {
+                    return t || v(e, 1, this.length), 128 & this[e] ? -1 * (255 - this[e] + 1) : this[e];
+                  }),
+                  (p.prototype.readInt16LE = function (e, t) {
+                    t || v(e, 2, this.length);
+                    t = this[e] | (this[e + 1] << 8);
+                    return 32768 & t ? 4294901760 | t : t;
+                  }),
+                  (p.prototype.readInt16BE = function (e, t) {
+                    t || v(e, 2, this.length);
+                    t = this[e + 1] | (this[e] << 8);
+                    return 32768 & t ? 4294901760 | t : t;
+                  }),
+                  (p.prototype.readInt32LE = function (e, t) {
+                    return (
+                      t || v(e, 4, this.length),
+                      this[e] | (this[e + 1] << 8) | (this[e + 2] << 16) | (this[e + 3] << 24)
+                    );
+                  }),
+                  (p.prototype.readInt32BE = function (e, t) {
+                    return (
+                      t || v(e, 4, this.length),
+                      (this[e] << 24) | (this[e + 1] << 16) | (this[e + 2] << 8) | this[e + 3]
+                    );
+                  }),
+                  (p.prototype.readFloatLE = function (e, t) {
+                    return t || v(e, 4, this.length), i.read(this, e, !0, 23, 4);
+                  }),
+                  (p.prototype.readFloatBE = function (e, t) {
+                    return t || v(e, 4, this.length), i.read(this, e, !1, 23, 4);
+                  }),
+                  (p.prototype.readDoubleLE = function (e, t) {
+                    return t || v(e, 8, this.length), i.read(this, e, !0, 52, 8);
+                  }),
+                  (p.prototype.readDoubleBE = function (e, t) {
+                    return t || v(e, 8, this.length), i.read(this, e, !1, 52, 8);
+                  }),
+                  (p.prototype.writeUIntLE = function (e, t, r, n) {
+                    (e = +e), (t |= 0), (r |= 0), n || j(this, e, t, r, Math.pow(2, 8 * r) - 1, 0);
+                    var s = 1,
+                      i = 0;
+                    for (this[t] = 255 & e; ++i < r && (s *= 256); ) this[t + i] = (e / s) & 255;
+                    return t + r;
+                  }),
+                  (p.prototype.writeUIntBE = function (e, t, r, n) {
+                    (e = +e), (t |= 0), (r |= 0), n || j(this, e, t, r, Math.pow(2, 8 * r) - 1, 0);
+                    var s = r - 1,
+                      i = 1;
+                    for (this[t + s] = 255 & e; 0 <= --s && (i *= 256); ) this[t + s] = (e / i) & 255;
+                    return t + r;
+                  }),
+                  (p.prototype.writeUInt8 = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 1, 255, 0),
+                      p.TYPED_ARRAY_SUPPORT || (e = Math.floor(e)),
+                      (this[t] = 255 & e),
+                      t + 1
+                    );
+                  }),
+                  (p.prototype.writeUInt16LE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 2, 65535, 0),
+                      p.TYPED_ARRAY_SUPPORT ? ((this[t] = 255 & e), (this[t + 1] = e >>> 8)) : w(this, e, t, !0),
+                      t + 2
+                    );
+                  }),
+                  (p.prototype.writeUInt16BE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 2, 65535, 0),
+                      p.TYPED_ARRAY_SUPPORT ? ((this[t] = e >>> 8), (this[t + 1] = 255 & e)) : w(this, e, t, !1),
+                      t + 2
+                    );
+                  }),
+                  (p.prototype.writeUInt32LE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 4, 4294967295, 0),
+                      p.TYPED_ARRAY_SUPPORT
+                        ? ((this[t + 3] = e >>> 24),
+                          (this[t + 2] = e >>> 16),
+                          (this[t + 1] = e >>> 8),
+                          (this[t] = 255 & e))
+                        : x(this, e, t, !0),
+                      t + 4
+                    );
+                  }),
+                  (p.prototype.writeUInt32BE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 4, 4294967295, 0),
+                      p.TYPED_ARRAY_SUPPORT
+                        ? ((this[t] = e >>> 24),
+                          (this[t + 1] = e >>> 16),
+                          (this[t + 2] = e >>> 8),
+                          (this[t + 3] = 255 & e))
+                        : x(this, e, t, !1),
+                      t + 4
+                    );
+                  }),
+                  (p.prototype.writeIntLE = function (e, t, r, n) {
+                    (e = +e), (t |= 0), n || j(this, e, t, r, (n = Math.pow(2, 8 * r - 1)) - 1, -n);
+                    var s = 0,
+                      i = 1,
+                      o = 0;
+                    for (this[t] = 255 & e; ++s < r && (i *= 256); )
+                      e < 0 && 0 === o && 0 !== this[t + s - 1] && (o = 1), (this[t + s] = (((e / i) >> 0) - o) & 255);
+                    return t + r;
+                  }),
+                  (p.prototype.writeIntBE = function (e, t, r, n) {
+                    (e = +e), (t |= 0), n || j(this, e, t, r, (n = Math.pow(2, 8 * r - 1)) - 1, -n);
+                    var s = r - 1,
+                      i = 1,
+                      o = 0;
+                    for (this[t + s] = 255 & e; 0 <= --s && (i *= 256); )
+                      e < 0 && 0 === o && 0 !== this[t + s + 1] && (o = 1), (this[t + s] = (((e / i) >> 0) - o) & 255);
+                    return t + r;
+                  }),
+                  (p.prototype.writeInt8 = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 1, 127, -128),
+                      p.TYPED_ARRAY_SUPPORT || (e = Math.floor(e)),
+                      (this[t] = 255 & (e = e < 0 ? 255 + e + 1 : e)),
+                      t + 1
+                    );
+                  }),
+                  (p.prototype.writeInt16LE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 2, 32767, -32768),
+                      p.TYPED_ARRAY_SUPPORT ? ((this[t] = 255 & e), (this[t + 1] = e >>> 8)) : w(this, e, t, !0),
+                      t + 2
+                    );
+                  }),
+                  (p.prototype.writeInt16BE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 2, 32767, -32768),
+                      p.TYPED_ARRAY_SUPPORT ? ((this[t] = e >>> 8), (this[t + 1] = 255 & e)) : w(this, e, t, !1),
+                      t + 2
+                    );
+                  }),
+                  (p.prototype.writeInt32LE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 4, 2147483647, -2147483648),
+                      p.TYPED_ARRAY_SUPPORT
+                        ? ((this[t] = 255 & e),
+                          (this[t + 1] = e >>> 8),
+                          (this[t + 2] = e >>> 16),
+                          (this[t + 3] = e >>> 24))
+                        : x(this, e, t, !0),
+                      t + 4
+                    );
+                  }),
+                  (p.prototype.writeInt32BE = function (e, t, r) {
+                    return (
+                      (e = +e),
+                      (t |= 0),
+                      r || j(this, e, t, 4, 2147483647, -2147483648),
+                      e < 0 && (e = 4294967295 + e + 1),
+                      p.TYPED_ARRAY_SUPPORT
+                        ? ((this[t] = e >>> 24),
+                          (this[t + 1] = e >>> 16),
+                          (this[t + 2] = e >>> 8),
+                          (this[t + 3] = 255 & e))
+                        : x(this, e, t, !1),
+                      t + 4
+                    );
+                  }),
+                  (p.prototype.writeFloatLE = function (e, t, r) {
+                    return _(this, e, t, !0, r);
+                  }),
+                  (p.prototype.writeFloatBE = function (e, t, r) {
+                    return _(this, e, t, !1, r);
+                  }),
+                  (p.prototype.writeDoubleLE = function (e, t, r) {
+                    return S(this, e, t, !0, r);
+                  }),
+                  (p.prototype.writeDoubleBE = function (e, t, r) {
+                    return S(this, e, t, !1, r);
+                  }),
+                  (p.prototype.copy = function (e, t, r, n) {
+                    if (
+                      ((r = r || 0),
+                      n || 0 === n || (n = this.length),
+                      t >= e.length && (t = e.length),
+                      (n = 0 < n && n < r ? r : n) === r)
+                    )
+                      return 0;
+                    if (0 === e.length || 0 === this.length) return 0;
+                    if ((t = t || 0) < 0) throw new RangeError('targetStart out of bounds');
+                    if (r < 0 || r >= this.length) throw new RangeError('sourceStart out of bounds');
+                    if (n < 0) throw new RangeError('sourceEnd out of bounds');
+                    n > this.length && (n = this.length);
+                    var s,
+                      i = (n = e.length - t < n - r ? e.length - t + r : n) - r;
+                    if (this === e && r < t && t < n) for (s = i - 1; 0 <= s; --s) e[s + t] = this[s + r];
+                    else if (i < 1e3 || !p.TYPED_ARRAY_SUPPORT) for (s = 0; s < i; ++s) e[s + t] = this[s + r];
+                    else Uint8Array.prototype.set.call(e, this.subarray(r, r + i), t);
+                    return i;
+                  }),
+                  (p.prototype.fill = function (e, t, r, n) {
+                    if ('string' == typeof e) {
+                      var s;
+                      if (
+                        ('string' == typeof t
+                          ? ((n = t), (t = 0), (r = this.length))
+                          : 'string' == typeof r && ((n = r), (r = this.length)),
+                        1 !== e.length || ((s = e.charCodeAt(0)) < 256 && (e = s)),
+                        void 0 !== n && 'string' != typeof n)
+                      )
+                        throw new TypeError('encoding must be a string');
+                      if ('string' == typeof n && !p.isEncoding(n)) throw new TypeError('Unknown encoding: ' + n);
+                    } else 'number' == typeof e && (e &= 255);
+                    if (t < 0 || this.length < t || this.length < r) throw new RangeError('Out of range index');
+                    if (r <= t) return this;
+                    if (((t >>>= 0), (r = void 0 === r ? this.length : r >>> 0), 'number' == typeof (e = e || 0)))
+                      for (a = t; a < r; ++a) this[a] = e;
+                    else
+                      for (var i = p.isBuffer(e) ? e : A(new p(e, n).toString()), o = i.length, a = 0; a < r - t; ++a)
+                        this[a + t] = i[a % o];
+                    return this;
+                  });
+                var O = /[^+\/0-9A-Za-z-_]/g;
+                function A(e, t) {
+                  t = t || 1 / 0;
+                  for (var r, n = e.length, s = null, i = [], o = 0; o < n; ++o) {
+                    if (55295 < (r = e.charCodeAt(o)) && r < 57344) {
+                      if (!s) {
+                        if (56319 < r) {
+                          -1 < (t -= 3) && i.push(239, 191, 189);
+                          continue;
+                        }
+                        if (o + 1 === n) {
+                          -1 < (t -= 3) && i.push(239, 191, 189);
+                          continue;
+                        }
+                        s = r;
+                        continue;
+                      }
+                      if (r < 56320) {
+                        -1 < (t -= 3) && i.push(239, 191, 189), (s = r);
+                        continue;
+                      }
+                      r = 65536 + (((s - 55296) << 10) | (r - 56320));
+                    } else s && -1 < (t -= 3) && i.push(239, 191, 189);
+                    if (((s = null), r < 128)) {
+                      if (--t < 0) break;
+                      i.push(r);
+                    } else if (r < 2048) {
+                      if ((t -= 2) < 0) break;
+                      i.push((r >> 6) | 192, (63 & r) | 128);
+                    } else if (r < 65536) {
+                      if ((t -= 3) < 0) break;
+                      i.push((r >> 12) | 224, ((r >> 6) & 63) | 128, (63 & r) | 128);
+                    } else {
+                      if (!(r < 1114112)) throw new Error('Invalid code point');
+                      if ((t -= 4) < 0) break;
+                      i.push((r >> 18) | 240, ((r >> 12) & 63) | 128, ((r >> 6) & 63) | 128, (63 & r) | 128);
+                    }
+                  }
+                  return i;
+                }
+                function D(e) {
+                  return k.toByteArray(
+                    (function (e) {
+                      var t;
+                      if ((e = ((t = e).trim ? t.trim() : t.replace(/^\s+|\s+$/g, '')).replace(O, '')).length < 2)
+                        return '';
+                      for (; e.length % 4 != 0; ) e += '=';
+                      return e;
+                    })(e)
+                  );
+                }
+                function I(e, t, r, n) {
+                  for (var s = 0; s < n && !(s + r >= t.length || s >= e.length); ++s) t[s + r] = e[s];
+                  return s;
+                }
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {},
+              C('buffer').Buffer
+            );
+          },
+          { 'base64-js': 85, buffer: 89, ieee754: 346, isarray: 355 }
+        ],
+        90: [
+          function (e, t, r) {
+            t.exports = {
+              100: 'Continue',
+              101: 'Switching Protocols',
+              102: 'Processing',
+              200: 'OK',
+              201: 'Created',
+              202: 'Accepted',
+              203: 'Non-Authoritative Information',
+              204: 'No Content',
+              205: 'Reset Content',
+              206: 'Partial Content',
+              207: 'Multi-Status',
+              208: 'Already Reported',
+              226: 'IM Used',
+              300: 'Multiple Choices',
+              301: 'Moved Permanently',
+              302: 'Found',
+              303: 'See Other',
+              304: 'Not Modified',
+              305: 'Use Proxy',
+              307: 'Temporary Redirect',
+              308: 'Permanent Redirect',
+              400: 'Bad Request',
+              401: 'Unauthorized',
+              402: 'Payment Required',
+              403: 'Forbidden',
+              404: 'Not Found',
+              405: 'Method Not Allowed',
+              406: 'Not Acceptable',
+              407: 'Proxy Authentication Required',
+              408: 'Request Timeout',
+              409: 'Conflict',
+              410: 'Gone',
+              411: 'Length Required',
+              412: 'Precondition Failed',
+              413: 'Payload Too Large',
+              414: 'URI Too Long',
+              415: 'Unsupported Media Type',
+              416: 'Range Not Satisfiable',
+              417: 'Expectation Failed',
+              418: "I'm a teapot",
+              421: 'Misdirected Request',
+              422: 'Unprocessable Entity',
+              423: 'Locked',
+              424: 'Failed Dependency',
+              425: 'Unordered Collection',
+              426: 'Upgrade Required',
+              428: 'Precondition Required',
+              429: 'Too Many Requests',
+              431: 'Request Header Fields Too Large',
+              451: 'Unavailable For Legal Reasons',
+              500: 'Internal Server Error',
+              501: 'Not Implemented',
+              502: 'Bad Gateway',
+              503: 'Service Unavailable',
+              504: 'Gateway Timeout',
+              505: 'HTTP Version Not Supported',
+              506: 'Variant Also Negotiates',
+              507: 'Insufficient Storage',
+              508: 'Loop Detected',
+              509: 'Bandwidth Limit Exceeded',
+              510: 'Not Extended',
+              511: 'Network Authentication Required'
+            };
+          },
+          {}
+        ],
+        91: [
+          function (e, t, r) {
+            'use strict';
+            var n = Array.prototype.slice;
+            function s(e, t) {
+              if (!(this instanceof s)) return new s(e, t);
+              (this.src = e), (this._withAccess = t);
+            }
+            ((t.exports = s).prototype.withAccess = function (e) {
+              return (this._withAccess = !1 !== e), this;
+            }),
+              (s.prototype.pick = function (e) {
+                return (e = Array.isArray(e) ? e : n.call(arguments)).length && (this.keys = e), this;
+              }),
+              (s.prototype.to = function (e) {
+                if (((e = e || {}), !this.src)) return e;
+                var t = this.keys || Object.keys(this.src);
+                if (!this._withAccess) {
+                  for (var r = 0; r < t.length; r++) void 0 === e[(i = t[r])] && (e[i] = this.src[i]);
+                  return e;
+                }
+                for (r = 0; r < t.length; r++) {
+                  var n,
+                    s,
+                    i = t[r];
+                  void 0 === (n = e)[(s = i)] &&
+                    void 0 === n.__lookupGetter__(s) &&
+                    void 0 === n.__lookupSetter__(s) &&
+                    ((n = this.src.__lookupGetter__(i)),
+                    (s = this.src.__lookupSetter__(i)),
+                    n && e.__defineGetter__(i, n),
+                    s && e.__defineSetter__(i, s),
+                    n || s || (e[i] = this.src[i]));
+                }
+                return e;
+              }),
+              (s.prototype.override = s.prototype.toCover =
+                function (e) {
+                  for (var t = this.keys || Object.keys(this.src), r = 0; r < t.length; r++) {
+                    var n = t[r],
+                      s = (delete e[n], this.src.__lookupGetter__(n)),
+                      i = this.src.__lookupSetter__(n);
+                    s && e.__defineGetter__(n, s), i && e.__defineSetter__(n, i), s || i || (e[n] = this.src[n]);
+                  }
+                }),
+              (s.prototype.and = function (e) {
+                var t = {};
+                return this.to(t), (this.src = e), this.to(t), (this.src = t), this;
+              });
+          },
+          {}
+        ],
+        92: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-callable'),
+              i = e('../internals/try-to-string'),
+              o = n.TypeError;
+            t.exports = function (e) {
+              if (s(e)) return e;
+              throw o(i(e) + ' is not a function');
+            };
+          },
+          { '../internals/global': 160, '../internals/is-callable': 173, '../internals/try-to-string': 254 }
+        ],
+        93: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-constructor'),
+              i = e('../internals/try-to-string'),
+              o = n.TypeError;
+            t.exports = function (e) {
+              if (s(e)) return e;
+              throw o(i(e) + ' is not a constructor');
+            };
+          },
+          { '../internals/global': 160, '../internals/is-constructor': 174, '../internals/try-to-string': 254 }
+        ],
+        94: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-callable'),
+              i = n.String,
+              o = n.TypeError;
+            t.exports = function (e) {
+              if ('object' == typeof e || s(e)) return e;
+              throw o("Can't set " + i(e) + ' as a prototype');
+            };
+          },
+          { '../internals/global': 160, '../internals/is-callable': 173 }
+        ],
+        95: [
+          function (e, t, r) {
+            var n = e('../internals/well-known-symbol'),
+              s = e('../internals/object-create'),
+              e = e('../internals/object-define-property'),
+              i = n('unscopables'),
+              o = Array.prototype;
+            null == o[i] && e.f(o, i, { configurable: !0, value: s(null) }),
+              (t.exports = function (e) {
+                o[i][e] = !0;
+              });
+          },
+          {
+            '../internals/object-create': 193,
+            '../internals/object-define-property': 195,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        96: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/string-multibyte').charAt;
+            t.exports = function (e, t, r) {
+              return t + (r ? n(e, t).length : 1);
+            };
+          },
+          { '../internals/string-multibyte': 236 }
+        ],
+        97: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/object-is-prototype-of'),
+              i = n.TypeError;
+            t.exports = function (e, t) {
+              if (s(t, e)) return e;
+              throw i('Incorrect invocation');
+            };
+          },
+          { '../internals/global': 160, '../internals/object-is-prototype-of': 201 }
+        ],
+        98: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-object'),
+              i = n.String,
+              o = n.TypeError;
+            t.exports = function (e) {
+              if (s(e)) return e;
+              throw o(i(e) + ' is not an object');
+            };
+          },
+          { '../internals/global': 160, '../internals/is-object': 177 }
+        ],
+        99: [
+          function (e, t, r) {
+            t.exports = 'undefined' != typeof ArrayBuffer && 'undefined' != typeof DataView;
+          },
+          {}
+        ],
+        100: [
+          function (e, t, r) {
+            'use strict';
+            function n(e) {
+              return !!p(e) && ((e = d(e)), f(I, e) || f(C, e));
+            }
+            var s,
+              i,
+              o,
+              a = e('../internals/array-buffer-native'),
+              c = e('../internals/descriptors'),
+              l = e('../internals/global'),
+              u = e('../internals/is-callable'),
+              p = e('../internals/is-object'),
+              f = e('../internals/has-own-property'),
+              d = e('../internals/classof'),
+              h = e('../internals/try-to-string'),
+              m = e('../internals/create-non-enumerable-property'),
+              y = e('../internals/redefine'),
+              b = e('../internals/object-define-property').f,
+              g = e('../internals/object-is-prototype-of'),
+              v = e('../internals/object-get-prototype-of'),
+              j = e('../internals/object-set-prototype-of'),
+              w = e('../internals/well-known-symbol'),
+              e = e('../internals/uid'),
+              x = l.Int8Array,
+              T = x && x.prototype,
+              k = l.Uint8ClampedArray,
+              k = k && k.prototype,
+              E = x && v(x),
+              _ = T && v(T),
+              x = Object.prototype,
+              S = l.TypeError,
+              w = w('toStringTag'),
+              O = e('TYPED_ARRAY_TAG'),
+              A = e('TYPED_ARRAY_CONSTRUCTOR'),
+              D = a && !!j && 'Opera' !== d(l.opera),
+              e = !1,
+              I = {
+                Int8Array: 1,
+                Uint8Array: 1,
+                Uint8ClampedArray: 1,
+                Int16Array: 2,
+                Uint16Array: 2,
+                Int32Array: 4,
+                Uint32Array: 4,
+                Float32Array: 4,
+                Float64Array: 8
+              },
+              C = { BigInt64Array: 8, BigUint64Array: 8 };
+            for (s in I) (o = (i = l[s]) && i.prototype) ? m(o, A, i) : (D = !1);
+            for (s in C) (o = (i = l[s]) && i.prototype) && m(o, A, i);
+            if (
+              (!D || !u(E) || E === Function.prototype) &&
+              ((E = function () {
+                throw S('Incorrect invocation');
+              }),
+              D)
+            )
+              for (s in I) l[s] && j(l[s], E);
+            if ((!D || !_ || _ === x) && ((_ = E.prototype), D)) for (s in I) l[s] && j(l[s].prototype, _);
+            if ((D && v(k) !== _ && j(k, _), c && !f(_, w)))
+              for (s in ((e = !0),
+              b(_, w, {
+                get: function () {
+                  return p(this) ? this[O] : void 0;
+                }
+              }),
+              I))
+                l[s] && m(l[s], O, s);
+            t.exports = {
+              NATIVE_ARRAY_BUFFER_VIEWS: D,
+              TYPED_ARRAY_CONSTRUCTOR: A,
+              TYPED_ARRAY_TAG: e && O,
+              aTypedArray: function (e) {
+                if (n(e)) return e;
+                throw S('Target is not a typed array');
+              },
+              aTypedArrayConstructor: function (e) {
+                if (!u(e) || (j && !g(E, e))) throw S(h(e) + ' is not a typed array constructor');
+                return e;
+              },
+              exportTypedArrayMethod: function (t, r, e, n) {
+                if (c) {
+                  if (e)
+                    for (var s in I) {
+                      s = l[s];
+                      if (s && f(s.prototype, t))
+                        try {
+                          delete s.prototype[t];
+                        } catch (e) {
+                          try {
+                            s.prototype[t] = r;
+                          } catch (e) {}
+                        }
+                    }
+                  (_[t] && !e) || y(_, t, (!e && D && T[t]) || r, n);
+                }
+              },
+              exportTypedArrayStaticMethod: function (e, t, r) {
+                var n, s;
+                if (c) {
+                  if (j) {
+                    if (r)
+                      for (n in I)
+                        if ((s = l[n]) && f(s, e))
+                          try {
+                            delete s[e];
+                          } catch (e) {}
+                    if (E[e] && !r) return;
+                    try {
+                      return y(E, e, (!r && D && E[e]) || t);
+                    } catch (e) {}
+                  }
+                  for (n in I) !(s = l[n]) || (s[e] && !r) || y(s, e, t);
+                }
+              },
+              isView: function (e) {
+                if (!p(e)) return !1;
+                e = d(e);
+                return 'DataView' === e || f(I, e) || f(C, e);
+              },
+              isTypedArray: n,
+              TypedArray: E,
+              TypedArrayPrototype: _
+            };
+          },
+          {
+            '../internals/array-buffer-native': 99,
+            '../internals/classof': 121,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/descriptors': 131,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/is-callable': 173,
+            '../internals/is-object': 177,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-prototype-of': 200,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/object-set-prototype-of': 205,
+            '../internals/redefine': 219,
+            '../internals/try-to-string': 254,
+            '../internals/uid': 260,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        101: [
+          function (e, M, L) {
+            'use strict';
+            function r(e) {
+              return [255 & e];
+            }
+            function n(e) {
+              return [255 & e, (e >> 8) & 255];
+            }
+            function s(e) {
+              return [255 & e, (e >> 8) & 255, (e >> 16) & 255, (e >> 24) & 255];
+            }
+            function t(e) {
+              return (e[3] << 24) | (e[2] << 16) | (e[1] << 8) | e[0];
+            }
+            function B(e) {
+              return C(e, 23, 4);
+            }
+            function q(e) {
+              return C(e, 52, 8);
+            }
+            function i(e, t) {
+              z(e[T], t, {
+                get: function () {
+                  return w(this)[t];
+                }
+              });
+            }
+            function o(e, t, r, n) {
+              if (((r = y(r)), (e = w(e)), r + t > e.byteLength)) throw I(k);
+              var s = w(e.buffer).bytes,
+                r = r + e.byteOffset,
+                e = H(s, r, r + t);
+              return n ? e : J(e);
+            }
+            function a(e, t, r, n, s, i) {
+              if (((r = y(r)), (e = w(e)), r + t > e.byteLength)) throw I(k);
+              for (var o = w(e.buffer).bytes, a = r + e.byteOffset, c = n(+s), l = 0; l < t; l++)
+                o[a + l] = c[i ? l : t - l - 1];
+            }
+            var c = e('../internals/global'),
+              l = e('../internals/function-uncurry-this'),
+              u = e('../internals/descriptors'),
+              F = e('../internals/array-buffer-native'),
+              p = e('../internals/function-name'),
+              f = e('../internals/create-non-enumerable-property'),
+              d = e('../internals/redefine-all'),
+              h = e('../internals/fails'),
+              m = e('../internals/an-instance'),
+              U = e('../internals/to-integer-or-infinity'),
+              G = e('../internals/to-length'),
+              y = e('../internals/to-index'),
+              b = e('../internals/ieee754'),
+              X = e('../internals/object-get-prototype-of'),
+              g = e('../internals/object-set-prototype-of'),
+              V = e('../internals/object-get-own-property-names').f,
+              z = e('../internals/object-define-property').f,
+              W = e('../internals/array-fill'),
+              H = e('../internals/array-slice-simple'),
+              v = e('../internals/set-to-string-tag'),
+              e = e('../internals/internal-state'),
+              K = p.PROPER,
+              j = p.CONFIGURABLE,
+              w = e.get,
+              x = e.set,
+              p = 'ArrayBuffer',
+              e = 'DataView',
+              T = 'prototype',
+              k = 'Wrong index',
+              E = c[p],
+              _ = E,
+              S = _ && _[T],
+              O = c[e],
+              A = O && O[T],
+              D = Object.prototype,
+              Y = c.Array,
+              I = c.RangeError,
+              $ = l(W),
+              J = l([].reverse),
+              C = b.pack,
+              N = b.unpack;
+            if (F) {
+              var R = K && E.name !== p;
+              if (
+                h(function () {
+                  E(1);
+                }) &&
+                h(function () {
+                  new E(-1);
+                }) &&
+                !h(function () {
+                  return new E(), new E(1.5), new E(NaN), R && !j;
+                })
+              )
+                R && j && f(E, 'name', p);
+              else {
+                (_ = function (e) {
+                  return m(this, S), new E(y(e));
+                })[T] = S;
+                for (var P, Z = V(E), Q = 0; Z.length > Q; ) (P = Z[Q++]) in _ || f(_, P, E[P]);
+                S.constructor = _;
+              }
+              g && X(A) !== D && g(A, D);
+              var c = new O(new _(2)),
+                ee = l(A.setInt8);
+              c.setInt8(0, 2147483648),
+                c.setInt8(1, 2147483649),
+                (!c.getInt8(0) && c.getInt8(1)) ||
+                  d(
+                    A,
+                    {
+                      setInt8: function (e, t) {
+                        ee(this, e, (t << 24) >> 24);
+                      },
+                      setUint8: function (e, t) {
+                        ee(this, e, (t << 24) >> 24);
+                      }
+                    },
+                    { unsafe: !0 }
+                  );
+            } else
+              (S = (_ = function (e) {
+                m(this, S);
+                e = y(e);
+                x(this, { bytes: $(Y(e), 0), byteLength: e }), u || (this.byteLength = e);
+              })[T]),
+                (A = (O = function (e, t, r) {
+                  m(this, A), m(e, S);
+                  var n = w(e).byteLength,
+                    t = U(t);
+                  if (t < 0 || n < t) throw I('Wrong offset');
+                  if (n < t + (r = void 0 === r ? n - t : G(r))) throw I('Wrong length');
+                  x(this, { buffer: e, byteLength: r, byteOffset: t }),
+                    u || ((this.buffer = e), (this.byteLength = r), (this.byteOffset = t));
+                })[T]),
+                u && (i(_, 'byteLength'), i(O, 'buffer'), i(O, 'byteLength'), i(O, 'byteOffset')),
+                d(A, {
+                  getInt8: function (e) {
+                    return (o(this, 1, e)[0] << 24) >> 24;
+                  },
+                  getUint8: function (e) {
+                    return o(this, 1, e)[0];
+                  },
+                  getInt16: function (e) {
+                    e = o(this, 2, e, 1 < arguments.length ? arguments[1] : void 0);
+                    return (((e[1] << 8) | e[0]) << 16) >> 16;
+                  },
+                  getUint16: function (e) {
+                    e = o(this, 2, e, 1 < arguments.length ? arguments[1] : void 0);
+                    return (e[1] << 8) | e[0];
+                  },
+                  getInt32: function (e) {
+                    return t(o(this, 4, e, 1 < arguments.length ? arguments[1] : void 0));
+                  },
+                  getUint32: function (e) {
+                    return t(o(this, 4, e, 1 < arguments.length ? arguments[1] : void 0)) >>> 0;
+                  },
+                  getFloat32: function (e) {
+                    return N(o(this, 4, e, 1 < arguments.length ? arguments[1] : void 0), 23);
+                  },
+                  getFloat64: function (e) {
+                    return N(o(this, 8, e, 1 < arguments.length ? arguments[1] : void 0), 52);
+                  },
+                  setInt8: function (e, t) {
+                    a(this, 1, e, r, t);
+                  },
+                  setUint8: function (e, t) {
+                    a(this, 1, e, r, t);
+                  },
+                  setInt16: function (e, t) {
+                    a(this, 2, e, n, t, 2 < arguments.length ? arguments[2] : void 0);
+                  },
+                  setUint16: function (e, t) {
+                    a(this, 2, e, n, t, 2 < arguments.length ? arguments[2] : void 0);
+                  },
+                  setInt32: function (e, t) {
+                    a(this, 4, e, s, t, 2 < arguments.length ? arguments[2] : void 0);
+                  },
+                  setUint32: function (e, t) {
+                    a(this, 4, e, s, t, 2 < arguments.length ? arguments[2] : void 0);
+                  },
+                  setFloat32: function (e, t) {
+                    a(this, 4, e, B, t, 2 < arguments.length ? arguments[2] : void 0);
+                  },
+                  setFloat64: function (e, t) {
+                    a(this, 8, e, q, t, 2 < arguments.length ? arguments[2] : void 0);
+                  }
+                });
+            v(_, p), v(O, e), (M.exports = { ArrayBuffer: _, DataView: O });
+          },
+          {
+            '../internals/an-instance': 97,
+            '../internals/array-buffer-native': 99,
+            '../internals/array-fill': 103,
+            '../internals/array-slice-simple': 113,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/descriptors': 131,
+            '../internals/fails': 147,
+            '../internals/function-name': 153,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/ieee754': 166,
+            '../internals/internal-state': 170,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-get-prototype-of': 200,
+            '../internals/object-set-prototype-of': 205,
+            '../internals/redefine-all': 218,
+            '../internals/set-to-string-tag': 231,
+            '../internals/to-index': 243,
+            '../internals/to-integer-or-infinity': 245,
+            '../internals/to-length': 246
+          }
+        ],
+        102: [
+          function (e, t, r) {
+            'use strict';
+            var c = e('../internals/to-object'),
+              l = e('../internals/to-absolute-index'),
+              u = e('../internals/length-of-array-like'),
+              p = Math.min;
+            t.exports =
+              [].copyWithin ||
+              function (e, t) {
+                var r = c(this),
+                  n = u(r),
+                  s = l(e, n),
+                  i = l(t, n),
+                  e = 2 < arguments.length ? arguments[2] : void 0,
+                  o = p((void 0 === e ? n : l(e, n)) - i, n - s),
+                  a = 1;
+                for (i < s && s < i + o && ((a = -1), (i += o - 1), (s += o - 1)); 0 < o--; )
+                  i in r ? (r[s] = r[i]) : delete r[s], (s += a), (i += a);
+                return r;
+              };
+          },
+          {
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-object': 247
+          }
+        ],
+        103: [
+          function (e, t, r) {
+            'use strict';
+            var o = e('../internals/to-object'),
+              a = e('../internals/to-absolute-index'),
+              c = e('../internals/length-of-array-like');
+            t.exports = function (e) {
+              for (
+                var t = o(this),
+                  r = c(t),
+                  n = arguments.length,
+                  s = a(1 < n ? arguments[1] : void 0, r),
+                  n = 2 < n ? arguments[2] : void 0,
+                  i = void 0 === n ? r : a(n, r);
+                s < i;
+
+              )
+                t[s++] = e;
+              return t;
+            };
+          },
+          {
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-object': 247
+          }
+        ],
+        104: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-iteration').forEach,
+              e = e('../internals/array-method-is-strict')('forEach');
+            t.exports = e
+              ? [].forEach
+              : function (e) {
+                  return n(this, e, 1 < arguments.length ? arguments[1] : void 0);
+                };
+          },
+          { '../internals/array-iteration': 108, '../internals/array-method-is-strict': 111 }
+        ],
+        105: [
+          function (e, t, r) {
+            var i = e('../internals/length-of-array-like');
+            t.exports = function (e, t) {
+              for (var r = 0, n = i(t), s = new e(n); r < n; ) s[r] = t[r++];
+              return s;
+            };
+          },
+          { '../internals/length-of-array-like': 185 }
+        ],
+        106: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/global'),
+              f = e('../internals/function-bind-context'),
+              d = e('../internals/function-call'),
+              h = e('../internals/to-object'),
+              m = e('../internals/call-with-safe-iteration-closing'),
+              y = e('../internals/is-array-iterator-method'),
+              b = e('../internals/is-constructor'),
+              g = e('../internals/length-of-array-like'),
+              v = e('../internals/create-property'),
+              j = e('../internals/get-iterator'),
+              w = e('../internals/get-iterator-method'),
+              x = n.Array;
+            t.exports = function (e) {
+              var t,
+                r,
+                n,
+                s,
+                i,
+                o,
+                a = h(e),
+                e = b(this),
+                c = arguments.length,
+                l = 1 < c ? arguments[1] : void 0,
+                u = void 0 !== l,
+                c = (u && (l = f(l, 2 < c ? arguments[2] : void 0)), w(a)),
+                p = 0;
+              if (!c || (this == x && y(c)))
+                for (t = g(a), r = e ? new this(t) : x(t); p < t; p++) (o = u ? l(a[p], p) : a[p]), v(r, p, o);
+              else
+                for (i = (s = j(a, c)).next, r = e ? new this() : []; !(n = d(i, s)).done; p++)
+                  (o = u ? m(s, l, [n.value, p], !0) : n.value), v(r, p, o);
+              return (r.length = p), r;
+            };
+          },
+          {
+            '../internals/call-with-safe-iteration-closing': 118,
+            '../internals/create-property': 128,
+            '../internals/function-bind-context': 150,
+            '../internals/function-call': 152,
+            '../internals/get-iterator': 157,
+            '../internals/get-iterator-method': 156,
+            '../internals/global': 160,
+            '../internals/is-array-iterator-method': 171,
+            '../internals/is-constructor': 174,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247
+          }
+        ],
+        107: [
+          function (e, t, r) {
+            function n(a) {
+              return function (e, t, r) {
+                var n,
+                  s = c(e),
+                  i = u(s),
+                  o = l(r, i);
+                if (a && t != t) {
+                  for (; o < i; ) if ((n = s[o++]) != n) return !0;
+                } else for (; o < i; o++) if ((a || o in s) && s[o] === t) return a || o || 0;
+                return !a && -1;
+              };
+            }
+            var c = e('../internals/to-indexed-object'),
+              l = e('../internals/to-absolute-index'),
+              u = e('../internals/length-of-array-like');
+            t.exports = { includes: n(!0), indexOf: n(!1) };
+          },
+          {
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        108: [
+          function (e, t, r) {
+            function n(f) {
+              var d = 1 == f,
+                h = 2 == f,
+                m = 3 == f,
+                y = 4 == f,
+                b = 6 == f,
+                g = 7 == f,
+                v = 5 == f || b;
+              return function (e, t, r, n) {
+                for (
+                  var s,
+                    i,
+                    o = x(e),
+                    a = w(o),
+                    c = j(t, r),
+                    l = T(a),
+                    u = 0,
+                    t = n || k,
+                    p = d ? t(e, l) : h || g ? t(e, 0) : void 0;
+                  u < l;
+                  u++
+                )
+                  if ((v || u in a) && ((i = c((s = a[u]), u, o)), f))
+                    if (d) p[u] = i;
+                    else if (i)
+                      switch (f) {
+                        case 3:
+                          return !0;
+                        case 5:
+                          return s;
+                        case 6:
+                          return u;
+                        case 2:
+                          E(p, s);
+                      }
+                    else
+                      switch (f) {
+                        case 4:
+                          return !1;
+                        case 7:
+                          E(p, s);
+                      }
+                return b ? -1 : m || y ? y : p;
+              };
+            }
+            var j = e('../internals/function-bind-context'),
+              s = e('../internals/function-uncurry-this'),
+              w = e('../internals/indexed-object'),
+              x = e('../internals/to-object'),
+              T = e('../internals/length-of-array-like'),
+              k = e('../internals/array-species-create'),
+              E = s([].push);
+            t.exports = {
+              forEach: n(0),
+              map: n(1),
+              filter: n(2),
+              some: n(3),
+              every: n(4),
+              find: n(5),
+              findIndex: n(6),
+              filterReject: n(7)
+            };
+          },
+          {
+            '../internals/array-species-create': 117,
+            '../internals/function-bind-context': 150,
+            '../internals/function-uncurry-this': 154,
+            '../internals/indexed-object': 167,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247
+          }
+        ],
+        109: [
+          function (e, t, r) {
+            'use strict';
+            var s = e('../internals/function-apply'),
+              i = e('../internals/to-indexed-object'),
+              o = e('../internals/to-integer-or-infinity'),
+              a = e('../internals/length-of-array-like'),
+              e = e('../internals/array-method-is-strict'),
+              c = Math.min,
+              l = [].lastIndexOf,
+              u = !!l && 1 / [1].lastIndexOf(1, -0) < 0,
+              e = e('lastIndexOf');
+            t.exports =
+              u || !e
+                ? function (e) {
+                    if (u) return s(l, this, arguments) || 0;
+                    var t = i(this),
+                      r = a(t),
+                      n = r - 1;
+                    for ((n = 1 < arguments.length ? c(n, o(arguments[1])) : n) < 0 && (n = r + n); 0 <= n; n--)
+                      if (n in t && t[n] === e) return n || 0;
+                    return -1;
+                  }
+                : l;
+          },
+          {
+            '../internals/array-method-is-strict': 111,
+            '../internals/function-apply': 149,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-indexed-object': 244,
+            '../internals/to-integer-or-infinity': 245
+          }
+        ],
+        110: [
+          function (e, t, r) {
+            var n = e('../internals/fails'),
+              s = e('../internals/well-known-symbol'),
+              i = e('../internals/engine-v8-version'),
+              o = s('species');
+            t.exports = function (t) {
+              return (
+                51 <= i ||
+                !n(function () {
+                  var e = [];
+                  return (
+                    ((e.constructor = {})[o] = function () {
+                      return { foo: 1 };
+                    }),
+                    1 !== e[t](Boolean).foo
+                  );
+                })
+              );
+            };
+          },
+          { '../internals/engine-v8-version': 143, '../internals/fails': 147, '../internals/well-known-symbol': 265 }
+        ],
+        111: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/fails');
+            t.exports = function (e, t) {
+              var r = [][e];
+              return (
+                !!r &&
+                n(function () {
+                  r.call(
+                    null,
+                    t ||
+                      function () {
+                        return 1;
+                      },
+                    1
+                  );
+                })
+              );
+            };
+          },
+          { '../internals/fails': 147 }
+        ],
+        112: [
+          function (e, t, r) {
+            function n(l) {
+              return function (e, t, r, n) {
+                u(t);
+                var s = p(e),
+                  i = f(s),
+                  o = d(s),
+                  a = l ? o - 1 : 0,
+                  c = l ? -1 : 1;
+                if (r < 2)
+                  for (;;) {
+                    if (a in i) {
+                      (n = i[a]), (a += c);
+                      break;
+                    }
+                    if (((a += c), l ? a < 0 : o <= a)) throw h('Reduce of empty array with no initial value');
+                  }
+                for (; l ? 0 <= a : a < o; a += c) a in i && (n = t(n, i[a], a, s));
+                return n;
+              };
+            }
+            var s = e('../internals/global'),
+              u = e('../internals/a-callable'),
+              p = e('../internals/to-object'),
+              f = e('../internals/indexed-object'),
+              d = e('../internals/length-of-array-like'),
+              h = s.TypeError;
+            t.exports = { left: n(!1), right: n(!0) };
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/global': 160,
+            '../internals/indexed-object': 167,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247
+          }
+        ],
+        113: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              c = e('../internals/to-absolute-index'),
+              l = e('../internals/length-of-array-like'),
+              u = e('../internals/create-property'),
+              p = n.Array,
+              f = Math.max;
+            t.exports = function (e, t, r) {
+              for (
+                var n = l(e), s = c(t, n), i = c(void 0 === r ? n : r, n), o = p(f(i - s, 0)), a = 0;
+                s < i;
+                s++, a++
+              )
+                u(o, a, e[s]);
+              return (o.length = a), o;
+            };
+          },
+          {
+            '../internals/create-property': 128,
+            '../internals/global': 160,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242
+          }
+        ],
+        114: [
+          function (e, t, r) {
+            e = e('../internals/function-uncurry-this');
+            t.exports = e([].slice);
+          },
+          { '../internals/function-uncurry-this': 154 }
+        ],
+        115: [
+          function (e, t, r) {
+            function g(e, t) {
+              var r = e.length,
+                n = j(r / 2);
+              if (r < 8) {
+                for (var s, i, o = e, a = t, c = o.length, l = 1; l < c; ) {
+                  for (s = o[(i = l)]; i && 0 < a(o[i - 1], s); ) o[i] = o[--i];
+                  i !== l++ && (o[i] = s);
+                }
+                return o;
+              }
+              for (
+                var u = e, p = g(v(e, 0, n), t), f = g(v(e, n), t), d = t, h = p.length, m = f.length, y = 0, b = 0;
+                y < h || b < m;
+
+              )
+                u[y + b] = y < h && b < m ? (d(p[y], f[b]) <= 0 ? p[y++] : f[b++]) : y < h ? p[y++] : f[b++];
+              return u;
+            }
+            var v = e('../internals/array-slice-simple'),
+              j = Math.floor;
+            t.exports = g;
+          },
+          { '../internals/array-slice-simple': 113 }
+        ],
+        116: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-array'),
+              i = e('../internals/is-constructor'),
+              o = e('../internals/is-object'),
+              a = e('../internals/well-known-symbol')('species'),
+              c = n.Array;
+            t.exports = function (e) {
+              var t;
+              return (
+                s(e) &&
+                  ((t = e.constructor),
+                  ((i(t) && (t === c || s(t.prototype))) || (o(t) && null === (t = t[a]))) && (t = void 0)),
+                void 0 === t ? c : t
+              );
+            };
+          },
+          {
+            '../internals/global': 160,
+            '../internals/is-array': 172,
+            '../internals/is-constructor': 174,
+            '../internals/is-object': 177,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        117: [
+          function (e, t, r) {
+            var n = e('../internals/array-species-constructor');
+            t.exports = function (e, t) {
+              return new (n(e))(0 === t ? 0 : t);
+            };
+          },
+          { '../internals/array-species-constructor': 116 }
+        ],
+        118: [
+          function (e, t, r) {
+            var s = e('../internals/an-object'),
+              i = e('../internals/iterator-close');
+            t.exports = function (t, e, r, n) {
+              try {
+                return n ? e(s(r)[0], r[1]) : e(r);
+              } catch (e) {
+                i(t, 'throw', e);
+              }
+            };
+          },
+          { '../internals/an-object': 98, '../internals/iterator-close': 182 }
+        ],
+        119: [
+          function (e, t, r) {
+            var s = e('../internals/well-known-symbol')('iterator'),
+              i = !1;
+            try {
+              var n = 0,
+                o = {
+                  next: function () {
+                    return { done: !!n++ };
+                  },
+                  return: function () {
+                    i = !0;
+                  }
+                };
+              (o[s] = function () {
+                return this;
+              }),
+                Array.from(o, function () {
+                  throw 2;
+                });
+            } catch (e) {}
+            t.exports = function (e, t) {
+              if (!t && !i) return !1;
+              var r = !1;
+              try {
+                var n = {};
+                (n[s] = function () {
+                  return {
+                    next: function () {
+                      return { done: (r = !0) };
+                    }
+                  };
+                }),
+                  e(n);
+              } catch (e) {}
+              return r;
+            };
+          },
+          { '../internals/well-known-symbol': 265 }
+        ],
+        120: [
+          function (e, t, r) {
+            var e = e('../internals/function-uncurry-this'),
+              n = e({}.toString),
+              s = e(''.slice);
+            t.exports = function (e) {
+              return s(n(e), 8, -1);
+            };
+          },
+          { '../internals/function-uncurry-this': 154 }
+        ],
+        121: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/to-string-tag-support'),
+              i = e('../internals/is-callable'),
+              o = e('../internals/classof-raw'),
+              a = e('../internals/well-known-symbol')('toStringTag'),
+              c = n.Object,
+              l =
+                'Arguments' ==
+                o(
+                  (function () {
+                    return arguments;
+                  })()
+                );
+            t.exports = s
+              ? o
+              : function (e) {
+                  var t;
+                  return void 0 === e
+                    ? 'Undefined'
+                    : null === e
+                    ? 'Null'
+                    : 'string' ==
+                      typeof (t = (function (e, t) {
+                        try {
+                          return e[t];
+                        } catch (e) {}
+                      })((e = c(e)), a))
+                    ? t
+                    : l
+                    ? o(e)
+                    : 'Object' == (t = o(e)) && i(e.callee)
+                    ? 'Arguments'
+                    : t;
+                };
+          },
+          {
+            '../internals/classof-raw': 120,
+            '../internals/global': 160,
+            '../internals/is-callable': 173,
+            '../internals/to-string-tag-support': 252,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        122: [
+          function (e, t, r) {
+            var c = e('../internals/has-own-property'),
+              l = e('../internals/own-keys'),
+              u = e('../internals/object-get-own-property-descriptor'),
+              p = e('../internals/object-define-property');
+            t.exports = function (e, t, r) {
+              for (var n = l(t), s = p.f, i = u.f, o = 0; o < n.length; o++) {
+                var a = n[o];
+                c(e, a) || (r && c(r, a)) || s(e, a, i(t, a));
+              }
+            };
+          },
+          {
+            '../internals/has-own-property': 161,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/own-keys': 209
+          }
+        ],
+        123: [
+          function (e, t, r) {
+            var n = e('../internals/well-known-symbol')('match');
+            t.exports = function (t) {
+              var r = /./;
+              try {
+                '/./'[t](r);
+              } catch (e) {
+                try {
+                  return (r[n] = !1), '/./'[t](r);
+                } catch (e) {}
+              }
+              return !1;
+            };
+          },
+          { '../internals/well-known-symbol': 265 }
+        ],
+        124: [
+          function (e, t, r) {
+            e = e('../internals/fails');
+            t.exports = !e(function () {
+              function e() {}
+              return (e.prototype.constructor = null), Object.getPrototypeOf(new e()) !== e.prototype;
+            });
+          },
+          { '../internals/fails': 147 }
+        ],
+        125: [
+          function (e, t, r) {
+            'use strict';
+            function s() {
+              return this;
+            }
+            var i = e('../internals/iterators-core').IteratorPrototype,
+              o = e('../internals/object-create'),
+              a = e('../internals/create-property-descriptor'),
+              c = e('../internals/set-to-string-tag'),
+              l = e('../internals/iterators');
+            t.exports = function (e, t, r, n) {
+              t += ' Iterator';
+              return (e.prototype = o(i, { next: a(+!n, r) })), c(e, t, !1, !0), (l[t] = s), e;
+            };
+          },
+          {
+            '../internals/create-property-descriptor': 127,
+            '../internals/iterators': 184,
+            '../internals/iterators-core': 183,
+            '../internals/object-create': 193,
+            '../internals/set-to-string-tag': 231
+          }
+        ],
+        126: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              s = e('../internals/object-define-property'),
+              i = e('../internals/create-property-descriptor');
+            t.exports = n
+              ? function (e, t, r) {
+                  return s.f(e, t, i(1, r));
+                }
+              : function (e, t, r) {
+                  return (e[t] = r), e;
+                };
+          },
+          {
+            '../internals/create-property-descriptor': 127,
+            '../internals/descriptors': 131,
+            '../internals/object-define-property': 195
+          }
+        ],
+        127: [
+          function (e, t, r) {
+            t.exports = function (e, t) {
+              return { enumerable: !(1 & e), configurable: !(2 & e), writable: !(4 & e), value: t };
+            };
+          },
+          {}
+        ],
+        128: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/to-property-key'),
+              s = e('../internals/object-define-property'),
+              i = e('../internals/create-property-descriptor');
+            t.exports = function (e, t, r) {
+              t = n(t);
+              t in e ? s.f(e, t, i(0, r)) : (e[t] = r);
+            };
+          },
+          {
+            '../internals/create-property-descriptor': 127,
+            '../internals/object-define-property': 195,
+            '../internals/to-property-key': 251
+          }
+        ],
+        129: [
+          function (e, t, r) {
+            'use strict';
+            function m() {
+              return this;
+            }
+            var y = e('../internals/export'),
+              b = e('../internals/function-call'),
+              g = e('../internals/is-pure'),
+              n = e('../internals/function-name'),
+              v = e('../internals/is-callable'),
+              j = e('../internals/create-iterator-constructor'),
+              w = e('../internals/object-get-prototype-of'),
+              x = e('../internals/object-set-prototype-of'),
+              T = e('../internals/set-to-string-tag'),
+              k = e('../internals/create-non-enumerable-property'),
+              E = e('../internals/redefine'),
+              s = e('../internals/well-known-symbol'),
+              _ = e('../internals/iterators'),
+              e = e('../internals/iterators-core'),
+              S = n.PROPER,
+              O = n.CONFIGURABLE,
+              A = e.IteratorPrototype,
+              D = e.BUGGY_SAFARI_ITERATORS,
+              I = s('iterator'),
+              C = 'values';
+            t.exports = function (e, t, r, n, s, i, o) {
+              j(r, t, n);
+              function a(e) {
+                if (e === s && d) return d;
+                if (!D && e in p) return p[e];
+                switch (e) {
+                  case 'keys':
+                  case C:
+                  case 'entries':
+                    return function () {
+                      return new r(this, e);
+                    };
+                }
+                return function () {
+                  return new r(this);
+                };
+              }
+              var c,
+                l,
+                n = t + ' Iterator',
+                u = !1,
+                p = e.prototype,
+                f = p[I] || p['@@iterator'] || (s && p[s]),
+                d = (!D && f) || a(s),
+                h = ('Array' == t && p.entries) || f;
+              if (
+                (h &&
+                  (h = w(h.call(new e()))) !== Object.prototype &&
+                  h.next &&
+                  (g || w(h) === A || (x ? x(h, A) : v(h[I]) || E(h, I, m)), T(h, n, !0, !0), g && (_[n] = m)),
+                S &&
+                  s == C &&
+                  f &&
+                  f.name !== C &&
+                  (!g && O
+                    ? k(p, 'name', C)
+                    : ((u = !0),
+                      (d = function () {
+                        return b(f, this);
+                      }))),
+                s)
+              )
+                if (((c = { values: a(C), keys: i ? d : a('keys'), entries: a('entries') }), o))
+                  for (l in c) (!D && !u && l in p) || E(p, l, c[l]);
+                else y({ target: t, proto: !0, forced: D || u }, c);
+              return (g && !o) || p[I] === d || E(p, I, d, { name: s }), (_[t] = d), c;
+            };
+          },
+          {
+            '../internals/create-iterator-constructor': 125,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/function-name': 153,
+            '../internals/is-callable': 173,
+            '../internals/is-pure': 178,
+            '../internals/iterators': 184,
+            '../internals/iterators-core': 183,
+            '../internals/object-get-prototype-of': 200,
+            '../internals/object-set-prototype-of': 205,
+            '../internals/redefine': 219,
+            '../internals/set-to-string-tag': 231,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        130: [
+          function (e, t, r) {
+            var n = e('../internals/path'),
+              s = e('../internals/has-own-property'),
+              i = e('../internals/well-known-symbol-wrapped'),
+              o = e('../internals/object-define-property').f;
+            t.exports = function (e) {
+              var t = n.Symbol || (n.Symbol = {});
+              s(t, e) || o(t, e, { value: i.f(e) });
+            };
+          },
+          {
+            '../internals/has-own-property': 161,
+            '../internals/object-define-property': 195,
+            '../internals/path': 210,
+            '../internals/well-known-symbol-wrapped': 264
+          }
+        ],
+        131: [
+          function (e, t, r) {
+            e = e('../internals/fails');
+            t.exports = !e(function () {
+              return (
+                7 !=
+                Object.defineProperty({}, 1, {
+                  get: function () {
+                    return 7;
+                  }
+                })[1]
+              );
+            });
+          },
+          { '../internals/fails': 147 }
+        ],
+        132: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              e = e('../internals/is-object'),
+              s = n.document,
+              i = e(s) && e(s.createElement);
+            t.exports = function (e) {
+              return i ? s.createElement(e) : {};
+            };
+          },
+          { '../internals/global': 160, '../internals/is-object': 177 }
+        ],
+        133: [
+          function (e, t, r) {
+            t.exports = {
+              CSSRuleList: 0,
+              CSSStyleDeclaration: 0,
+              CSSValueList: 0,
+              ClientRectList: 0,
+              DOMRectList: 0,
+              DOMStringList: 0,
+              DOMTokenList: 1,
+              DataTransferItemList: 0,
+              FileList: 0,
+              HTMLAllCollection: 0,
+              HTMLCollection: 0,
+              HTMLFormElement: 0,
+              HTMLSelectElement: 0,
+              MediaList: 0,
+              MimeTypeArray: 0,
+              NamedNodeMap: 0,
+              NodeList: 1,
+              PaintRequestList: 0,
+              Plugin: 0,
+              PluginArray: 0,
+              SVGLengthList: 0,
+              SVGNumberList: 0,
+              SVGPathSegList: 0,
+              SVGPointList: 0,
+              SVGStringList: 0,
+              SVGTransformList: 0,
+              SourceBufferList: 0,
+              StyleSheetList: 0,
+              TextTrackCueList: 0,
+              TextTrackList: 0,
+              TouchList: 0
+            };
+          },
+          {}
+        ],
+        134: [
+          function (e, t, r) {
+            (e = e('../internals/document-create-element')('span').classList),
+              (e = e && e.constructor && e.constructor.prototype);
+            t.exports = e === Object.prototype ? void 0 : e;
+          },
+          { '../internals/document-create-element': 132 }
+        ],
+        135: [
+          function (e, t, r) {
+            e = e('../internals/engine-user-agent').match(/firefox\/(\d+)/i);
+            t.exports = !!e && +e[1];
+          },
+          { '../internals/engine-user-agent': 142 }
+        ],
+        136: [
+          function (e, t, r) {
+            t.exports = 'object' == typeof window && 'object' != typeof Deno;
+          },
+          {}
+        ],
+        137: [
+          function (e, t, r) {
+            e = e('../internals/engine-user-agent');
+            t.exports = /MSIE|Trident/.test(e);
+          },
+          { '../internals/engine-user-agent': 142 }
+        ],
+        138: [
+          function (e, t, r) {
+            var n = e('../internals/engine-user-agent'),
+              e = e('../internals/global');
+            t.exports = /ipad|iphone|ipod/i.test(n) && void 0 !== e.Pebble;
+          },
+          { '../internals/engine-user-agent': 142, '../internals/global': 160 }
+        ],
+        139: [
+          function (e, t, r) {
+            e = e('../internals/engine-user-agent');
+            t.exports = /(?:ipad|iphone|ipod).*applewebkit/i.test(e);
+          },
+          { '../internals/engine-user-agent': 142 }
+        ],
+        140: [
+          function (e, t, r) {
+            var n = e('../internals/classof-raw'),
+              e = e('../internals/global');
+            t.exports = 'process' == n(e.process);
+          },
+          { '../internals/classof-raw': 120, '../internals/global': 160 }
+        ],
+        141: [
+          function (e, t, r) {
+            e = e('../internals/engine-user-agent');
+            t.exports = /web0s(?!.*chrome)/i.test(e);
+          },
+          { '../internals/engine-user-agent': 142 }
+        ],
+        142: [
+          function (e, t, r) {
+            e = e('../internals/get-built-in');
+            t.exports = e('navigator', 'userAgent') || '';
+          },
+          { '../internals/get-built-in': 155 }
+        ],
+        143: [
+          function (e, t, r) {
+            var n,
+              s,
+              i = e('../internals/global'),
+              e = e('../internals/engine-user-agent'),
+              o = i.process,
+              i = i.Deno,
+              o = (o && o.versions) || (i && i.version),
+              i = o && o.v8;
+            !(s = i ? (0 < (n = i.split('.'))[0] && n[0] < 4 ? 1 : +(n[0] + n[1])) : s) &&
+              e &&
+              (!(n = e.match(/Edge\/(\d+)/)) || 74 <= n[1]) &&
+              (n = e.match(/Chrome\/(\d+)/)) &&
+              (s = +n[1]),
+              (t.exports = s);
+          },
+          { '../internals/engine-user-agent': 142, '../internals/global': 160 }
+        ],
+        144: [
+          function (e, t, r) {
+            e = e('../internals/engine-user-agent').match(/AppleWebKit\/(\d+)\./);
+            t.exports = !!e && +e[1];
+          },
+          { '../internals/engine-user-agent': 142 }
+        ],
+        145: [
+          function (e, t, r) {
+            t.exports = [
+              'constructor',
+              'hasOwnProperty',
+              'isPrototypeOf',
+              'propertyIsEnumerable',
+              'toLocaleString',
+              'toString',
+              'valueOf'
+            ];
+          },
+          {}
+        ],
+        146: [
+          function (e, t, r) {
+            var l = e('../internals/global'),
+              u = e('../internals/object-get-own-property-descriptor').f,
+              p = e('../internals/create-non-enumerable-property'),
+              f = e('../internals/redefine'),
+              d = e('../internals/set-global'),
+              h = e('../internals/copy-constructor-properties'),
+              m = e('../internals/is-forced');
+            t.exports = function (e, t) {
+              var r,
+                n,
+                s,
+                i = e.target,
+                o = e.global,
+                a = e.stat,
+                c = o ? l : a ? l[i] || d(i, {}) : (l[i] || {}).prototype;
+              if (c)
+                for (r in t) {
+                  if (
+                    ((n = t[r]),
+                    (s = e.noTargetGet ? (s = u(c, r)) && s.value : c[r]),
+                    !m(o ? r : i + (a ? '.' : '#') + r, e.forced) && void 0 !== s)
+                  ) {
+                    if (typeof n == typeof s) continue;
+                    h(n, s);
+                  }
+                  (e.sham || (s && s.sham)) && p(n, 'sham', !0), f(c, r, n, e);
+                }
+            };
+          },
+          {
+            '../internals/copy-constructor-properties': 122,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/global': 160,
+            '../internals/is-forced': 175,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/redefine': 219,
+            '../internals/set-global': 229
+          }
+        ],
+        147: [
+          function (e, t, r) {
+            t.exports = function (e) {
+              try {
+                return !!e();
+              } catch (e) {
+                return !0;
+              }
+            };
+          },
+          {}
+        ],
+        148: [
+          function (e, t, r) {
+            'use strict';
+            e('../modules/es.regexp.exec');
+            var c = e('../internals/function-uncurry-this'),
+              l = e('../internals/redefine'),
+              u = e('../internals/regexp-exec'),
+              p = e('../internals/fails'),
+              f = e('../internals/well-known-symbol'),
+              d = e('../internals/create-non-enumerable-property'),
+              h = f('species'),
+              m = RegExp.prototype;
+            t.exports = function (r, e, t, n) {
+              var o,
+                s = f(r),
+                a = !p(function () {
+                  var e = {};
+                  return (
+                    (e[s] = function () {
+                      return 7;
+                    }),
+                    7 != ''[r](e)
+                  );
+                }),
+                i =
+                  a &&
+                  !p(function () {
+                    var e = !1,
+                      t = /a/;
+                    return (
+                      'split' === r &&
+                        (((t = { constructor: {} }).constructor[h] = function () {
+                          return t;
+                        }),
+                        (t.flags = ''),
+                        (t[s] = /./[s])),
+                      (t.exec = function () {
+                        return (e = !0), null;
+                      }),
+                      t[s](''),
+                      !e
+                    );
+                  });
+              (a && i && !t) ||
+                ((o = c(/./[s])),
+                (i = e(s, ''[r], function (e, t, r, n, s) {
+                  var e = c(e),
+                    i = t.exec;
+                  return i === u || i === m.exec
+                    ? a && !s
+                      ? { done: !0, value: o(t, r, n) }
+                      : { done: !0, value: e(r, t, n) }
+                    : { done: !1 };
+                })),
+                l(String.prototype, r, i[0]),
+                l(m, s, i[1])),
+                n && d(m[s], 'sham', !0);
+            };
+          },
+          {
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/redefine': 219,
+            '../internals/regexp-exec': 221,
+            '../internals/well-known-symbol': 265,
+            '../modules/es.regexp.exec': 299
+          }
+        ],
+        149: [
+          function (e, t, r) {
+            var e = e('../internals/function-bind-native'),
+              n = Function.prototype,
+              s = n.apply,
+              i = n.call;
+            t.exports =
+              ('object' == typeof Reflect && Reflect.apply) ||
+              (e
+                ? i.bind(s)
+                : function () {
+                    return i.apply(s, arguments);
+                  });
+          },
+          { '../internals/function-bind-native': 151 }
+        ],
+        150: [
+          function (e, t, r) {
+            var n = e('../internals/function-uncurry-this'),
+              s = e('../internals/a-callable'),
+              i = e('../internals/function-bind-native'),
+              o = n(n.bind);
+            t.exports = function (e, t) {
+              return (
+                s(e),
+                void 0 === t
+                  ? e
+                  : i
+                  ? o(e, t)
+                  : function () {
+                      return e.apply(t, arguments);
+                    }
+              );
+            };
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/function-bind-native': 151,
+            '../internals/function-uncurry-this': 154
+          }
+        ],
+        151: [
+          function (e, t, r) {
+            e = e('../internals/fails');
+            t.exports = !e(function () {
+              var e = function () {}.bind();
+              return 'function' != typeof e || e.hasOwnProperty('prototype');
+            });
+          },
+          { '../internals/fails': 147 }
+        ],
+        152: [
+          function (e, t, r) {
+            var e = e('../internals/function-bind-native'),
+              n = Function.prototype.call;
+            t.exports = e
+              ? n.bind(n)
+              : function () {
+                  return n.apply(n, arguments);
+                };
+          },
+          { '../internals/function-bind-native': 151 }
+        ],
+        153: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              e = e('../internals/has-own-property'),
+              s = Function.prototype,
+              i = n && Object.getOwnPropertyDescriptor,
+              e = e(s, 'name'),
+              o = e && 'something' === function () {}.name,
+              n = e && (!n || i(s, 'name').configurable);
+            t.exports = { EXISTS: e, PROPER: o, CONFIGURABLE: n };
+          },
+          { '../internals/descriptors': 131, '../internals/has-own-property': 161 }
+        ],
+        154: [
+          function (e, t, r) {
+            var e = e('../internals/function-bind-native'),
+              n = Function.prototype,
+              s = n.bind,
+              i = n.call,
+              o = e && s.bind(i, i);
+            t.exports = e
+              ? function (e) {
+                  return e && o(e);
+                }
+              : function (e) {
+                  return (
+                    e &&
+                    function () {
+                      return i.apply(e, arguments);
+                    }
+                  );
+                };
+          },
+          { '../internals/function-bind-native': 151 }
+        ],
+        155: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-callable');
+            t.exports = function (e, t) {
+              return arguments.length < 2 ? ((r = n[e]), s(r) ? r : void 0) : n[e] && n[e][t];
+              var r;
+            };
+          },
+          { '../internals/global': 160, '../internals/is-callable': 173 }
+        ],
+        156: [
+          function (e, t, r) {
+            var n = e('../internals/classof'),
+              s = e('../internals/get-method'),
+              i = e('../internals/iterators'),
+              o = e('../internals/well-known-symbol')('iterator');
+            t.exports = function (e) {
+              if (null != e) return s(e, o) || s(e, '@@iterator') || i[n(e)];
+            };
+          },
+          {
+            '../internals/classof': 121,
+            '../internals/get-method': 158,
+            '../internals/iterators': 184,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        157: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/function-call'),
+              i = e('../internals/a-callable'),
+              o = e('../internals/an-object'),
+              a = e('../internals/try-to-string'),
+              c = e('../internals/get-iterator-method'),
+              l = n.TypeError;
+            t.exports = function (e, t) {
+              var r = arguments.length < 2 ? c(e) : t;
+              if (i(r)) return o(s(r, e));
+              throw l(a(e) + ' is not iterable');
+            };
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/an-object': 98,
+            '../internals/function-call': 152,
+            '../internals/get-iterator-method': 156,
+            '../internals/global': 160,
+            '../internals/try-to-string': 254
+          }
+        ],
+        158: [
+          function (e, t, r) {
+            var n = e('../internals/a-callable');
+            t.exports = function (e, t) {
+              e = e[t];
+              return null == e ? void 0 : n(e);
+            };
+          },
+          { '../internals/a-callable': 92 }
+        ],
+        159: [
+          function (e, t, r) {
+            var n = e('../internals/function-uncurry-this'),
+              s = e('../internals/to-object'),
+              f = Math.floor,
+              d = n(''.charAt),
+              h = n(''.replace),
+              m = n(''.slice),
+              y = /\$([$&'`]|\d{1,2}|<[^>]*>)/g,
+              b = /\$([$&'`]|\d{1,2})/g;
+            t.exports = function (i, o, a, c, l, e) {
+              var u = a + i.length,
+                p = c.length,
+                t = b;
+              return (
+                void 0 !== l && ((l = s(l)), (t = y)),
+                h(e, t, function (e, t) {
+                  var r;
+                  switch (d(t, 0)) {
+                    case '$':
+                      return '$';
+                    case '&':
+                      return i;
+                    case '`':
+                      return m(o, 0, a);
+                    case "'":
+                      return m(o, u);
+                    case '<':
+                      r = l[m(t, 1, -1)];
+                      break;
+                    default:
+                      var n,
+                        s = +t;
+                      if (0 == s) return e;
+                      if (p < s)
+                        return 0 !== (n = f(s / 10)) && n <= p
+                          ? void 0 === c[n - 1]
+                            ? d(t, 1)
+                            : c[n - 1] + d(t, 1)
+                          : e;
+                      r = c[s - 1];
+                  }
+                  return void 0 === r ? '' : r;
+                })
+              );
+            };
+          },
+          { '../internals/function-uncurry-this': 154, '../internals/to-object': 247 }
+        ],
+        160: [
+          function (e, r, t) {
+            !function (t) {
+              !function () {
+                function e(e) {
+                  return e && e.Math == Math && e;
+                }
+                r.exports =
+                  e('object' == typeof globalThis && globalThis) ||
+                  e('object' == typeof window && window) ||
+                  e('object' == typeof self && self) ||
+                  e('object' == typeof t && t) ||
+                  (function () {
+                    return this;
+                  })() ||
+                  Function('return this')();
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        161: [
+          function (e, t, r) {
+            var n = e('../internals/function-uncurry-this'),
+              s = e('../internals/to-object'),
+              i = n({}.hasOwnProperty);
+            t.exports =
+              Object.hasOwn ||
+              function (e, t) {
+                return i(s(e), t);
+              };
+          },
+          { '../internals/function-uncurry-this': 154, '../internals/to-object': 247 }
+        ],
+        162: [
+          function (e, t, r) {
+            t.exports = {};
+          },
+          {}
+        ],
+        163: [
+          function (e, t, r) {
+            var n = e('../internals/global');
+            t.exports = function (e, t) {
+              var r = n.console;
+              r && r.error && (1 == arguments.length ? r.error(e) : r.error(e, t));
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        164: [
+          function (e, t, r) {
+            e = e('../internals/get-built-in');
+            t.exports = e('document', 'documentElement');
+          },
+          { '../internals/get-built-in': 155 }
+        ],
+        165: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              s = e('../internals/fails'),
+              i = e('../internals/document-create-element');
+            t.exports =
+              !n &&
+              !s(function () {
+                return (
+                  7 !=
+                  Object.defineProperty(i('div'), 'a', {
+                    get: function () {
+                      return 7;
+                    }
+                  }).a
+                );
+              });
+          },
+          { '../internals/descriptors': 131, '../internals/document-create-element': 132, '../internals/fails': 147 }
+        ],
+        166: [
+          function (e, t, r) {
+            var f = e('../internals/global').Array,
+              d = Math.abs,
+              h = Math.pow,
+              m = Math.floor,
+              y = Math.log,
+              b = Math.LN2;
+            t.exports = {
+              pack: function (e, t, r) {
+                var n,
+                  s,
+                  i,
+                  o = f(r),
+                  a = 8 * r - t - 1,
+                  r = (1 << a) - 1,
+                  c = r >> 1,
+                  l = 23 === t ? h(2, -24) - h(2, -77) : 0,
+                  u = e < 0 || (0 === e && 1 / e < 0) ? 1 : 0,
+                  p = 0;
+                for (
+                  (e = d(e)) != e || e === 1 / 0
+                    ? ((s = e != e ? 1 : 0), (n = r))
+                    : ((n = m(y(e) / b)),
+                      e * (i = h(2, -n)) < 1 && (n--, (i *= 2)),
+                      2 <= (e += 1 <= n + c ? l / i : l * h(2, 1 - c)) * i && (n++, (i /= 2)),
+                      r <= n + c
+                        ? ((s = 0), (n = r))
+                        : 1 <= n + c
+                        ? ((s = (e * i - 1) * h(2, t)), (n += c))
+                        : ((s = e * h(2, c - 1) * h(2, t)), (n = 0)));
+                  8 <= t;
+
+                )
+                  (o[p++] = 255 & s), (s /= 256), (t -= 8);
+                for (n = (n << t) | s, a += t; 0 < a; ) (o[p++] = 255 & n), (n /= 256), (a -= 8);
+                return (o[--p] |= 128 * u), o;
+              },
+              unpack: function (e, t) {
+                var r,
+                  n = e.length,
+                  s = 8 * n - t - 1,
+                  i = (1 << s) - 1,
+                  o = i >> 1,
+                  a = s - 7,
+                  c = n - 1,
+                  s = e[c--],
+                  l = 127 & s;
+                for (s >>= 7; 0 < a; ) (l = 256 * l + e[c--]), (a -= 8);
+                for (r = l & ((1 << -a) - 1), l >>= -a, a += t; 0 < a; ) (r = 256 * r + e[c--]), (a -= 8);
+                if (0 === l) l = 1 - o;
+                else {
+                  if (l === i) return r ? NaN : s ? -1 / 0 : 1 / 0;
+                  (r += h(2, t)), (l -= o);
+                }
+                return (s ? -1 : 1) * r * h(2, l - t);
+              }
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        167: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/fails'),
+              o = e('../internals/classof-raw'),
+              a = n.Object,
+              c = s(''.split);
+            t.exports = i(function () {
+              return !a('z').propertyIsEnumerable(0);
+            })
+              ? function (e) {
+                  return 'String' == o(e) ? c(e, '') : a(e);
+                }
+              : a;
+          },
+          {
+            '../internals/classof-raw': 120,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160
+          }
+        ],
+        168: [
+          function (e, t, r) {
+            var n = e('../internals/is-callable'),
+              s = e('../internals/is-object'),
+              i = e('../internals/object-set-prototype-of');
+            t.exports = function (e, t, r) {
+              return i && n((t = t.constructor)) && t !== r && s((t = t.prototype)) && t !== r.prototype && i(e, t), e;
+            };
+          },
+          {
+            '../internals/is-callable': 173,
+            '../internals/is-object': 177,
+            '../internals/object-set-prototype-of': 205
+          }
+        ],
+        169: [
+          function (e, t, r) {
+            var n = e('../internals/function-uncurry-this'),
+              s = e('../internals/is-callable'),
+              e = e('../internals/shared-store'),
+              i = n(Function.toString);
+            s(e.inspectSource) ||
+              (e.inspectSource = function (e) {
+                return i(e);
+              }),
+              (t.exports = e.inspectSource);
+          },
+          {
+            '../internals/function-uncurry-this': 154,
+            '../internals/is-callable': 173,
+            '../internals/shared-store': 233
+          }
+        ],
+        170: [
+          function (e, t, r) {
+            var n,
+              s,
+              i,
+              o,
+              a,
+              c,
+              l,
+              u,
+              p = e('../internals/native-weak-map'),
+              f = e('../internals/global'),
+              d = e('../internals/function-uncurry-this'),
+              h = e('../internals/is-object'),
+              m = e('../internals/create-non-enumerable-property'),
+              y = e('../internals/has-own-property'),
+              b = e('../internals/shared-store'),
+              g = e('../internals/shared-key'),
+              e = e('../internals/hidden-keys'),
+              v = 'Object already initialized',
+              j = f.TypeError,
+              f = f.WeakMap;
+            (l =
+              p || b.state
+                ? ((n = b.state || (b.state = new f())),
+                  (s = d(n.get)),
+                  (i = d(n.has)),
+                  (o = d(n.set)),
+                  (a = function (e, t) {
+                    if (i(n, e)) throw new j(v);
+                    return (t.facade = e), o(n, e, t), t;
+                  }),
+                  (c = function (e) {
+                    return s(n, e) || {};
+                  }),
+                  function (e) {
+                    return i(n, e);
+                  })
+                : ((e[(u = g('state'))] = !0),
+                  (a = function (e, t) {
+                    if (y(e, u)) throw new j(v);
+                    return (t.facade = e), m(e, u, t), t;
+                  }),
+                  (c = function (e) {
+                    return y(e, u) ? e[u] : {};
+                  }),
+                  function (e) {
+                    return y(e, u);
+                  })),
+              (t.exports = {
+                set: a,
+                get: c,
+                has: l,
+                enforce: function (e) {
+                  return l(e) ? c(e) : a(e, {});
+                },
+                getterFor: function (t) {
+                  return function (e) {
+                    if (h(e) && (e = c(e)).type === t) return e;
+                    throw j('Incompatible receiver, ' + t + ' required');
+                  };
+                }
+              });
+          },
+          {
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/hidden-keys': 162,
+            '../internals/is-object': 177,
+            '../internals/native-weak-map': 189,
+            '../internals/shared-key': 232,
+            '../internals/shared-store': 233
+          }
+        ],
+        171: [
+          function (e, t, r) {
+            var n = e('../internals/well-known-symbol'),
+              s = e('../internals/iterators'),
+              i = n('iterator'),
+              o = Array.prototype;
+            t.exports = function (e) {
+              return void 0 !== e && (s.Array === e || o[i] === e);
+            };
+          },
+          { '../internals/iterators': 184, '../internals/well-known-symbol': 265 }
+        ],
+        172: [
+          function (e, t, r) {
+            var n = e('../internals/classof-raw');
+            t.exports =
+              Array.isArray ||
+              function (e) {
+                return 'Array' == n(e);
+              };
+          },
+          { '../internals/classof-raw': 120 }
+        ],
+        173: [
+          function (e, t, r) {
+            t.exports = function (e) {
+              return 'function' == typeof e;
+            };
+          },
+          {}
+        ],
+        174: [
+          function (e, t, r) {
+            function n() {}
+            function s(e) {
+              if (!c(e)) return !1;
+              try {
+                return d(n, f, e), !0;
+              } catch (e) {
+                return !1;
+              }
+            }
+            function i(e) {
+              if (!c(e)) return !1;
+              switch (l(e)) {
+                case 'AsyncFunction':
+                case 'GeneratorFunction':
+                case 'AsyncGeneratorFunction':
+                  return !1;
+              }
+              try {
+                return y || !!m(h, p(e));
+              } catch (e) {
+                return !0;
+              }
+            }
+            var o = e('../internals/function-uncurry-this'),
+              a = e('../internals/fails'),
+              c = e('../internals/is-callable'),
+              l = e('../internals/classof'),
+              u = e('../internals/get-built-in'),
+              p = e('../internals/inspect-source'),
+              f = [],
+              d = u('Reflect', 'construct'),
+              h = /^\s*(?:class|function)\b/,
+              m = o(h.exec),
+              y = !h.exec(n);
+            (i.sham = !0),
+              (t.exports =
+                !d ||
+                a(function () {
+                  var e;
+                  return (
+                    s(s.call) ||
+                    !s(Object) ||
+                    !s(function () {
+                      e = !0;
+                    }) ||
+                    e
+                  );
+                })
+                  ? i
+                  : s);
+          },
+          {
+            '../internals/classof': 121,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/get-built-in': 155,
+            '../internals/inspect-source': 169,
+            '../internals/is-callable': 173
+          }
+        ],
+        175: [
+          function (e, t, r) {
+            function n(e, t) {
+              return (e = c[a(e)]) == u || (e != l && (i(t) ? s(t) : !!t));
+            }
+            var s = e('../internals/fails'),
+              i = e('../internals/is-callable'),
+              o = /#|\.prototype\./,
+              a = (n.normalize = function (e) {
+                return String(e).replace(o, '.').toLowerCase();
+              }),
+              c = (n.data = {}),
+              l = (n.NATIVE = 'N'),
+              u = (n.POLYFILL = 'P');
+            t.exports = n;
+          },
+          { '../internals/fails': 147, '../internals/is-callable': 173 }
+        ],
+        176: [
+          function (e, t, r) {
+            var n = e('../internals/is-object'),
+              s = Math.floor;
+            t.exports =
+              Number.isInteger ||
+              function (e) {
+                return !n(e) && isFinite(e) && s(e) === e;
+              };
+          },
+          { '../internals/is-object': 177 }
+        ],
+        177: [
+          function (e, t, r) {
+            var n = e('../internals/is-callable');
+            t.exports = function (e) {
+              return 'object' == typeof e ? null !== e : n(e);
+            };
+          },
+          { '../internals/is-callable': 173 }
+        ],
+        178: [
+          function (e, t, r) {
+            t.exports = !1;
+          },
+          {}
+        ],
+        179: [
+          function (e, t, r) {
+            var n = e('../internals/is-object'),
+              s = e('../internals/classof-raw'),
+              i = e('../internals/well-known-symbol')('match');
+            t.exports = function (e) {
+              var t;
+              return n(e) && (void 0 !== (t = e[i]) ? !!t : 'RegExp' == s(e));
+            };
+          },
+          { '../internals/classof-raw': 120, '../internals/is-object': 177, '../internals/well-known-symbol': 265 }
+        ],
+        180: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/get-built-in'),
+              i = e('../internals/is-callable'),
+              o = e('../internals/object-is-prototype-of'),
+              e = e('../internals/use-symbol-as-uid'),
+              a = n.Object;
+            t.exports = e
+              ? function (e) {
+                  return 'symbol' == typeof e;
+                }
+              : function (e) {
+                  var t = s('Symbol');
+                  return i(t) && o(t.prototype, a(e));
+                };
+          },
+          {
+            '../internals/get-built-in': 155,
+            '../internals/global': 160,
+            '../internals/is-callable': 173,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/use-symbol-as-uid': 261
+          }
+        ],
+        181: [
+          function (e, t, r) {
+            function y(e, t) {
+              (this.stopped = e), (this.result = t);
+            }
+            var n = e('../internals/global'),
+              b = e('../internals/function-bind-context'),
+              g = e('../internals/function-call'),
+              v = e('../internals/an-object'),
+              j = e('../internals/try-to-string'),
+              w = e('../internals/is-array-iterator-method'),
+              x = e('../internals/length-of-array-like'),
+              T = e('../internals/object-is-prototype-of'),
+              k = e('../internals/get-iterator'),
+              E = e('../internals/get-iterator-method'),
+              _ = e('../internals/iterator-close'),
+              S = n.TypeError,
+              O = y.prototype;
+            t.exports = function (e, t, r) {
+              function n(e) {
+                return i && _(i, 'normal', e), new y(!0, e);
+              }
+              function s(e) {
+                return f ? (v(e), h ? m(e[0], e[1], n) : m(e[0], e[1])) : h ? m(e, n) : m(e);
+              }
+              var i,
+                o,
+                a,
+                c,
+                l,
+                u,
+                p = r && r.that,
+                f = !(!r || !r.AS_ENTRIES),
+                d = !(!r || !r.IS_ITERATOR),
+                h = !(!r || !r.INTERRUPTED),
+                m = b(t, p);
+              if (d) i = e;
+              else {
+                if (!(r = E(e))) throw S(j(e) + ' is not iterable');
+                if (w(r)) {
+                  for (o = 0, a = x(e); o < a; o++) if ((c = s(e[o])) && T(O, c)) return c;
+                  return new y(!1);
+                }
+                i = k(e, r);
+              }
+              for (l = i.next; !(u = g(l, i)).done; ) {
+                try {
+                  c = s(u.value);
+                } catch (e) {
+                  _(i, 'throw', e);
+                }
+                if ('object' == typeof c && c && T(O, c)) return c;
+              }
+              return new y(!1);
+            };
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/function-bind-context': 150,
+            '../internals/function-call': 152,
+            '../internals/get-iterator': 157,
+            '../internals/get-iterator-method': 156,
+            '../internals/global': 160,
+            '../internals/is-array-iterator-method': 171,
+            '../internals/iterator-close': 182,
+            '../internals/length-of-array-like': 185,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/try-to-string': 254
+          }
+        ],
+        182: [
+          function (e, t, r) {
+            var i = e('../internals/function-call'),
+              o = e('../internals/an-object'),
+              a = e('../internals/get-method');
+            t.exports = function (e, t, r) {
+              var n, s;
+              o(e);
+              try {
+                if (!(n = a(e, 'return'))) {
+                  if ('throw' === t) throw r;
+                  return r;
+                }
+                n = i(n, e);
+              } catch (e) {
+                (s = !0), (n = e);
+              }
+              if ('throw' === t) throw r;
+              if (s) throw n;
+              return o(n), r;
+            };
+          },
+          { '../internals/an-object': 98, '../internals/function-call': 152, '../internals/get-method': 158 }
+        ],
+        183: [
+          function (e, t, r) {
+            'use strict';
+            var n,
+              s,
+              i = e('../internals/fails'),
+              o = e('../internals/is-callable'),
+              a = e('../internals/object-create'),
+              c = e('../internals/object-get-prototype-of'),
+              l = e('../internals/redefine'),
+              u = e('../internals/well-known-symbol'),
+              e = e('../internals/is-pure'),
+              p = u('iterator'),
+              u = !1;
+            [].keys && ('next' in (s = [].keys()) ? (c = c(c(s))) !== Object.prototype && (n = c) : (u = !0)),
+              null == n ||
+              i(function () {
+                var e = {};
+                return n[p].call(e) !== e;
+              })
+                ? (n = {})
+                : e && (n = a(n)),
+              o(n[p]) ||
+                l(n, p, function () {
+                  return this;
+                }),
+              (t.exports = { IteratorPrototype: n, BUGGY_SAFARI_ITERATORS: u });
+          },
+          {
+            '../internals/fails': 147,
+            '../internals/is-callable': 173,
+            '../internals/is-pure': 178,
+            '../internals/object-create': 193,
+            '../internals/object-get-prototype-of': 200,
+            '../internals/redefine': 219,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        184: [
+          function (e, t, r) {
+            arguments[4][162][0].apply(r, arguments);
+          },
+          { dup: 162 }
+        ],
+        185: [
+          function (e, t, r) {
+            var n = e('../internals/to-length');
+            t.exports = function (e) {
+              return n(e.length);
+            };
+          },
+          { '../internals/to-length': 246 }
+        ],
+        186: [
+          function (e, t, r) {
+            var n,
+              s,
+              i,
+              o,
+              a,
+              c,
+              l,
+              u = e('../internals/global'),
+              p = e('../internals/function-bind-context'),
+              f = e('../internals/object-get-own-property-descriptor').f,
+              d = e('../internals/task').set,
+              h = e('../internals/engine-is-ios'),
+              m = e('../internals/engine-is-ios-pebble'),
+              y = e('../internals/engine-is-webos-webkit'),
+              b = e('../internals/engine-is-node'),
+              e = u.MutationObserver || u.WebKitMutationObserver,
+              g = u.document,
+              v = u.process,
+              j = u.Promise,
+              f = f(u, 'queueMicrotask'),
+              f = f && f.value;
+            f ||
+              ((n = function () {
+                var e, t;
+                for (b && (e = v.domain) && e.exit(); s; ) {
+                  (t = s.fn), (s = s.next);
+                  try {
+                    t();
+                  } catch (e) {
+                    throw (s ? o() : (i = void 0), e);
+                  }
+                }
+                (i = void 0), e && e.enter();
+              }),
+              (o =
+                h || b || y || !e || !g
+                  ? !m && j && j.resolve
+                    ? (((h = j.resolve(void 0)).constructor = j),
+                      (l = p(h.then, h)),
+                      function () {
+                        l(n);
+                      })
+                    : b
+                    ? function () {
+                        v.nextTick(n);
+                      }
+                    : ((d = p(d, u)),
+                      function () {
+                        d(n);
+                      })
+                  : ((a = !0),
+                    (c = g.createTextNode('')),
+                    new e(n).observe(c, { characterData: !0 }),
+                    function () {
+                      c.data = a = !a;
+                    }))),
+              (t.exports =
+                f ||
+                function (e) {
+                  e = { fn: e, next: void 0 };
+                  i && (i.next = e), s || ((s = e), o()), (i = e);
+                });
+          },
+          {
+            '../internals/engine-is-ios': 139,
+            '../internals/engine-is-ios-pebble': 138,
+            '../internals/engine-is-node': 140,
+            '../internals/engine-is-webos-webkit': 141,
+            '../internals/function-bind-context': 150,
+            '../internals/global': 160,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/task': 240
+          }
+        ],
+        187: [
+          function (e, t, r) {
+            e = e('../internals/native-symbol');
+            t.exports = e && !!Symbol.for && !!Symbol.keyFor;
+          },
+          { '../internals/native-symbol': 188 }
+        ],
+        188: [
+          function (e, t, r) {
+            var n = e('../internals/engine-v8-version'),
+              e = e('../internals/fails');
+            t.exports =
+              !!Object.getOwnPropertySymbols &&
+              !e(function () {
+                var e = Symbol();
+                return !String(e) || !(Object(e) instanceof Symbol) || (!Symbol.sham && n && n < 41);
+              });
+          },
+          { '../internals/engine-v8-version': 143, '../internals/fails': 147 }
+        ],
+        189: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-callable'),
+              e = e('../internals/inspect-source'),
+              n = n.WeakMap;
+            t.exports = s(n) && /native code/.test(e(n));
+          },
+          { '../internals/global': 160, '../internals/inspect-source': 169, '../internals/is-callable': 173 }
+        ],
+        190: [
+          function (e, t, r) {
+            'use strict';
+            function n(e) {
+              var r, n;
+              (this.promise = new e(function (e, t) {
+                if (void 0 !== r || void 0 !== n) throw TypeError('Bad Promise constructor');
+                (r = e), (n = t);
+              })),
+                (this.resolve = s(r)),
+                (this.reject = s(n));
+            }
+            var s = e('../internals/a-callable');
+            t.exports.f = function (e) {
+              return new n(e);
+            };
+          },
+          { '../internals/a-callable': 92 }
+        ],
+        191: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/is-regexp'),
+              i = n.TypeError;
+            t.exports = function (e) {
+              if (s(e)) throw i("The method doesn't accept regular expressions");
+              return e;
+            };
+          },
+          { '../internals/global': 160, '../internals/is-regexp': 179 }
+        ],
+        192: [
+          function (e, t, r) {
+            'use strict';
+            var f = e('../internals/descriptors'),
+              n = e('../internals/function-uncurry-this'),
+              d = e('../internals/function-call'),
+              s = e('../internals/fails'),
+              h = e('../internals/object-keys'),
+              m = e('../internals/object-get-own-property-symbols'),
+              y = e('../internals/object-property-is-enumerable'),
+              b = e('../internals/to-object'),
+              g = e('../internals/indexed-object'),
+              i = Object.assign,
+              o = Object.defineProperty,
+              v = n([].concat);
+            t.exports =
+              !i ||
+              s(function () {
+                if (
+                  f &&
+                  1 !==
+                    i(
+                      { b: 1 },
+                      i(
+                        o({}, 'a', {
+                          enumerable: !0,
+                          get: function () {
+                            o(this, 'b', { value: 3, enumerable: !1 });
+                          }
+                        }),
+                        { b: 2 }
+                      )
+                    ).b
+                )
+                  return !0;
+                var e = {},
+                  t = {},
+                  r = Symbol(),
+                  n = 'abcdefghijklmnopqrst';
+                return (
+                  (e[r] = 7),
+                  n.split('').forEach(function (e) {
+                    t[e] = e;
+                  }),
+                  7 != i({}, e)[r] || h(i({}, t)).join('') != n
+                );
+              })
+                ? function (e, t) {
+                    for (var r = b(e), n = arguments.length, s = 1, i = m.f, o = y.f; s < n; )
+                      for (var a, c = g(arguments[s++]), l = i ? v(h(c), i(c)) : h(c), u = l.length, p = 0; p < u; )
+                        (a = l[p++]), (f && !d(o, c, a)) || (r[a] = c[a]);
+                    return r;
+                  }
+                : i;
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/fails': 147,
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/indexed-object': 167,
+            '../internals/object-get-own-property-symbols': 199,
+            '../internals/object-keys': 203,
+            '../internals/object-property-is-enumerable': 204,
+            '../internals/to-object': 247
+          }
+        ],
+        193: [
+          function (e, t, r) {
+            function n() {}
+            function s(e) {
+              e.write(m('')), e.close();
+              var t = e.parentWindow.Object;
+              return (e = null), t;
+            }
+            var i,
+              o = e('../internals/an-object'),
+              a = e('../internals/object-define-properties'),
+              c = e('../internals/enum-bug-keys'),
+              l = e('../internals/hidden-keys'),
+              u = e('../internals/html'),
+              p = e('../internals/document-create-element'),
+              e = e('../internals/shared-key'),
+              f = 'prototype',
+              d = 'script',
+              h = e('IE_PROTO'),
+              m = function (e) {
+                return '<' + d + '>' + e + '</' + d + '>';
+              },
+              y = function () {
+                try {
+                  i = new ActiveXObject('htmlfile');
+                } catch (e) {}
+                y =
+                  'undefined' == typeof document || (document.domain && i)
+                    ? s(i)
+                    : ((e = p('iframe')),
+                      (t = 'java' + d + ':'),
+                      (e.style.display = 'none'),
+                      u.appendChild(e),
+                      (e.src = String(t)),
+                      (t = e.contentWindow.document).open(),
+                      t.write(m('document.F=Object')),
+                      t.close(),
+                      t.F);
+                for (var e, t, r = c.length; r--; ) delete y[f][c[r]];
+                return y();
+              };
+            (l[h] = !0),
+              (t.exports =
+                Object.create ||
+                function (e, t) {
+                  var r;
+                  return (
+                    null !== e ? ((n[f] = o(e)), (r = new n()), (n[f] = null), (r[h] = e)) : (r = y()),
+                    void 0 === t ? r : a.f(r, t)
+                  );
+                });
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/document-create-element': 132,
+            '../internals/enum-bug-keys': 145,
+            '../internals/hidden-keys': 162,
+            '../internals/html': 164,
+            '../internals/object-define-properties': 194,
+            '../internals/shared-key': 232
+          }
+        ],
+        194: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              s = e('../internals/v8-prototype-define-bug'),
+              a = e('../internals/object-define-property'),
+              c = e('../internals/an-object'),
+              l = e('../internals/to-indexed-object'),
+              u = e('../internals/object-keys');
+            r.f =
+              n && !s
+                ? Object.defineProperties
+                : function (e, t) {
+                    c(e);
+                    for (var r, n = l(t), s = u(t), i = s.length, o = 0; o < i; ) a.f(e, (r = s[o++]), n[r]);
+                    return e;
+                  };
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/descriptors': 131,
+            '../internals/object-define-property': 195,
+            '../internals/object-keys': 203,
+            '../internals/to-indexed-object': 244,
+            '../internals/v8-prototype-define-bug': 262
+          }
+        ],
+        195: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/descriptors'),
+              i = e('../internals/ie8-dom-define'),
+              o = e('../internals/v8-prototype-define-bug'),
+              a = e('../internals/an-object'),
+              c = e('../internals/to-property-key'),
+              l = n.TypeError,
+              u = Object.defineProperty,
+              p = Object.getOwnPropertyDescriptor,
+              f = 'enumerable',
+              d = 'configurable',
+              h = 'writable';
+            r.f = s
+              ? o
+                ? function (e, t, r) {
+                    var n;
+                    return (
+                      a(e),
+                      (t = c(t)),
+                      a(r),
+                      'function' == typeof e &&
+                        'prototype' === t &&
+                        'value' in r &&
+                        h in r &&
+                        !r[h] &&
+                        (n = p(e, t)) &&
+                        n[h] &&
+                        ((e[t] = r.value),
+                        (r = { configurable: (d in r ? r : n)[d], enumerable: (f in r ? r : n)[f], writable: !1 })),
+                      u(e, t, r)
+                    );
+                  }
+                : u
+              : function (e, t, r) {
+                  if ((a(e), (t = c(t)), a(r), i))
+                    try {
+                      return u(e, t, r);
+                    } catch (e) {}
+                  if ('get' in r || 'set' in r) throw l('Accessors not supported');
+                  return 'value' in r && (e[t] = r.value), e;
+                };
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/descriptors': 131,
+            '../internals/global': 160,
+            '../internals/ie8-dom-define': 165,
+            '../internals/to-property-key': 251,
+            '../internals/v8-prototype-define-bug': 262
+          }
+        ],
+        196: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              s = e('../internals/function-call'),
+              i = e('../internals/object-property-is-enumerable'),
+              o = e('../internals/create-property-descriptor'),
+              a = e('../internals/to-indexed-object'),
+              c = e('../internals/to-property-key'),
+              l = e('../internals/has-own-property'),
+              u = e('../internals/ie8-dom-define'),
+              p = Object.getOwnPropertyDescriptor;
+            r.f = n
+              ? p
+              : function (e, t) {
+                  if (((e = a(e)), (t = c(t)), u))
+                    try {
+                      return p(e, t);
+                    } catch (e) {}
+                  if (l(e, t)) return o(!s(i.f, e, t), e[t]);
+                };
+          },
+          {
+            '../internals/create-property-descriptor': 127,
+            '../internals/descriptors': 131,
+            '../internals/function-call': 152,
+            '../internals/has-own-property': 161,
+            '../internals/ie8-dom-define': 165,
+            '../internals/object-property-is-enumerable': 204,
+            '../internals/to-indexed-object': 244,
+            '../internals/to-property-key': 251
+          }
+        ],
+        197: [
+          function (e, t, r) {
+            var n = e('../internals/classof-raw'),
+              s = e('../internals/to-indexed-object'),
+              i = e('../internals/object-get-own-property-names').f,
+              o = e('../internals/array-slice-simple'),
+              a =
+                'object' == typeof window && window && Object.getOwnPropertyNames
+                  ? Object.getOwnPropertyNames(window)
+                  : [];
+            t.exports.f = function (e) {
+              if (!a || 'Window' != n(e)) return i(s(e));
+              try {
+                return i(e);
+              } catch (e) {
+                return o(a);
+              }
+            };
+          },
+          {
+            '../internals/array-slice-simple': 113,
+            '../internals/classof-raw': 120,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        198: [
+          function (e, t, r) {
+            var n = e('../internals/object-keys-internal'),
+              s = e('../internals/enum-bug-keys').concat('length', 'prototype');
+            r.f =
+              Object.getOwnPropertyNames ||
+              function (e) {
+                return n(e, s);
+              };
+          },
+          { '../internals/enum-bug-keys': 145, '../internals/object-keys-internal': 202 }
+        ],
+        199: [
+          function (e, t, r) {
+            r.f = Object.getOwnPropertySymbols;
+          },
+          {}
+        ],
+        200: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/has-own-property'),
+              i = e('../internals/is-callable'),
+              o = e('../internals/to-object'),
+              a = e('../internals/shared-key'),
+              e = e('../internals/correct-prototype-getter'),
+              c = a('IE_PROTO'),
+              l = n.Object,
+              u = l.prototype;
+            t.exports = e
+              ? l.getPrototypeOf
+              : function (e) {
+                  e = o(e);
+                  if (s(e, c)) return e[c];
+                  var t = e.constructor;
+                  return i(t) && e instanceof t ? t.prototype : e instanceof l ? u : null;
+                };
+          },
+          {
+            '../internals/correct-prototype-getter': 124,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/is-callable': 173,
+            '../internals/shared-key': 232,
+            '../internals/to-object': 247
+          }
+        ],
+        201: [
+          function (e, t, r) {
+            e = e('../internals/function-uncurry-this');
+            t.exports = e({}.isPrototypeOf);
+          },
+          { '../internals/function-uncurry-this': 154 }
+        ],
+        202: [
+          function (e, t, r) {
+            var n = e('../internals/function-uncurry-this'),
+              o = e('../internals/has-own-property'),
+              a = e('../internals/to-indexed-object'),
+              c = e('../internals/array-includes').indexOf,
+              l = e('../internals/hidden-keys'),
+              u = n([].push);
+            t.exports = function (e, t) {
+              var r,
+                n = a(e),
+                s = 0,
+                i = [];
+              for (r in n) !o(l, r) && o(n, r) && u(i, r);
+              for (; t.length > s; ) !o(n, (r = t[s++])) || ~c(i, r) || u(i, r);
+              return i;
+            };
+          },
+          {
+            '../internals/array-includes': 107,
+            '../internals/function-uncurry-this': 154,
+            '../internals/has-own-property': 161,
+            '../internals/hidden-keys': 162,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        203: [
+          function (e, t, r) {
+            var n = e('../internals/object-keys-internal'),
+              s = e('../internals/enum-bug-keys');
+            t.exports =
+              Object.keys ||
+              function (e) {
+                return n(e, s);
+              };
+          },
+          { '../internals/enum-bug-keys': 145, '../internals/object-keys-internal': 202 }
+        ],
+        204: [
+          function (e, t, r) {
+            'use strict';
+            var n = {}.propertyIsEnumerable,
+              s = Object.getOwnPropertyDescriptor,
+              i = s && !n.call({ 1: 2 }, 1);
+            r.f = i
+              ? function (e) {
+                  e = s(this, e);
+                  return !!e && e.enumerable;
+                }
+              : n;
+          },
+          {}
+        ],
+        205: [
+          function (e, t, r) {
+            var s = e('../internals/function-uncurry-this'),
+              i = e('../internals/an-object'),
+              o = e('../internals/a-possible-prototype');
+            t.exports =
+              Object.setPrototypeOf ||
+              ('__proto__' in {}
+                ? (function () {
+                    var r,
+                      n = !1,
+                      e = {};
+                    try {
+                      (r = s(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set))(e, []),
+                        (n = e instanceof Array);
+                    } catch (e) {}
+                    return function (e, t) {
+                      return i(e), o(t), n ? r(e, t) : (e.__proto__ = t), e;
+                    };
+                  })()
+                : void 0);
+          },
+          {
+            '../internals/a-possible-prototype': 94,
+            '../internals/an-object': 98,
+            '../internals/function-uncurry-this': 154
+          }
+        ],
+        206: [
+          function (e, t, r) {
+            function n(a) {
+              return function (e) {
+                for (var t, r = u(e), n = l(r), s = n.length, i = 0, o = []; i < s; )
+                  (t = n[i++]), (c && !p(r, t)) || f(o, a ? [t, r[t]] : r[t]);
+                return o;
+              };
+            }
+            var c = e('../internals/descriptors'),
+              s = e('../internals/function-uncurry-this'),
+              l = e('../internals/object-keys'),
+              u = e('../internals/to-indexed-object'),
+              p = s(e('../internals/object-property-is-enumerable').f),
+              f = s([].push);
+            t.exports = { entries: n(!0), values: n(!1) };
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/function-uncurry-this': 154,
+            '../internals/object-keys': 203,
+            '../internals/object-property-is-enumerable': 204,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        207: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/to-string-tag-support'),
+              s = e('../internals/classof');
+            t.exports = n
+              ? {}.toString
+              : function () {
+                  return '[object ' + s(this) + ']';
+                };
+          },
+          { '../internals/classof': 121, '../internals/to-string-tag-support': 252 }
+        ],
+        208: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/function-call'),
+              i = e('../internals/is-callable'),
+              o = e('../internals/is-object'),
+              a = n.TypeError;
+            t.exports = function (e, t) {
+              var r, n;
+              if ('string' === t && i((r = e.toString)) && !o((n = s(r, e)))) return n;
+              if (i((r = e.valueOf)) && !o((n = s(r, e)))) return n;
+              if ('string' !== t && i((r = e.toString)) && !o((n = s(r, e)))) return n;
+              throw a("Can't convert object to primitive value");
+            };
+          },
+          {
+            '../internals/function-call': 152,
+            '../internals/global': 160,
+            '../internals/is-callable': 173,
+            '../internals/is-object': 177
+          }
+        ],
+        209: [
+          function (e, t, r) {
+            var n = e('../internals/get-built-in'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/object-get-own-property-names'),
+              o = e('../internals/object-get-own-property-symbols'),
+              a = e('../internals/an-object'),
+              c = s([].concat);
+            t.exports =
+              n('Reflect', 'ownKeys') ||
+              function (e) {
+                var t = i.f(a(e)),
+                  r = o.f;
+                return r ? c(t, r(e)) : t;
+              };
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/function-uncurry-this': 154,
+            '../internals/get-built-in': 155,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-get-own-property-symbols': 199
+          }
+        ],
+        210: [
+          function (e, t, r) {
+            e = e('../internals/global');
+            t.exports = e;
+          },
+          { '../internals/global': 160 }
+        ],
+        211: [
+          function (e, t, r) {
+            t.exports = function (e) {
+              try {
+                return { error: !1, value: e() };
+              } catch (e) {
+                return { error: !0, value: e };
+              }
+            };
+          },
+          {}
+        ],
+        212: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/promise-native-constructor'),
+              i = e('../internals/is-callable'),
+              o = e('../internals/is-forced'),
+              a = e('../internals/inspect-source'),
+              c = e('../internals/well-known-symbol'),
+              l = e('../internals/engine-is-browser'),
+              u = e('../internals/is-pure'),
+              p = e('../internals/engine-v8-version'),
+              f = s && s.prototype,
+              d = c('species'),
+              h = !1,
+              m = i(n.PromiseRejectionEvent),
+              e = o('Promise', function () {
+                var e = a(s),
+                  t = e !== String(s);
+                if (!t && 66 === p) return !0;
+                if (u && (!f.catch || !f.finally)) return !0;
+                if (51 <= p && /native code/.test(e)) return !1;
+                function r(e) {
+                  e(
+                    function () {},
+                    function () {}
+                  );
+                }
+                e = new s(function (e) {
+                  e(1);
+                });
+                return ((e.constructor = {})[d] = r), !(h = e.then(function () {}) instanceof r) || (!t && l && !m);
+              });
+            t.exports = { CONSTRUCTOR: e, REJECTION_EVENT: m, SUBCLASSING: h };
+          },
+          {
+            '../internals/engine-is-browser': 136,
+            '../internals/engine-v8-version': 143,
+            '../internals/global': 160,
+            '../internals/inspect-source': 169,
+            '../internals/is-callable': 173,
+            '../internals/is-forced': 175,
+            '../internals/is-pure': 178,
+            '../internals/promise-native-constructor': 213,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        213: [
+          function (e, t, r) {
+            e = e('../internals/global');
+            t.exports = e.Promise;
+          },
+          { '../internals/global': 160 }
+        ],
+        214: [
+          function (e, t, r) {
+            var n = e('../internals/an-object'),
+              s = e('../internals/is-object'),
+              i = e('../internals/new-promise-capability');
+            t.exports = function (e, t) {
+              if ((n(e), s(t) && t.constructor === e)) return t;
+              e = i.f(e);
+              return (0, e.resolve)(t), e.promise;
+            };
+          },
+          { '../internals/an-object': 98, '../internals/is-object': 177, '../internals/new-promise-capability': 190 }
+        ],
+        215: [
+          function (e, t, r) {
+            var n = e('../internals/promise-native-constructor'),
+              s = e('../internals/check-correctness-of-iteration'),
+              e = e('../internals/promise-constructor-detection').CONSTRUCTOR;
+            t.exports =
+              e ||
+              !s(function (e) {
+                n.all(e).then(void 0, function () {});
+              });
+          },
+          {
+            '../internals/check-correctness-of-iteration': 119,
+            '../internals/promise-constructor-detection': 212,
+            '../internals/promise-native-constructor': 213
+          }
+        ],
+        216: [
+          function (e, t, r) {
+            var n = e('../internals/object-define-property').f;
+            t.exports = function (e, t, r) {
+              r in e ||
+                n(e, r, {
+                  configurable: !0,
+                  get: function () {
+                    return t[r];
+                  },
+                  set: function (e) {
+                    t[r] = e;
+                  }
+                });
+            };
+          },
+          { '../internals/object-define-property': 195 }
+        ],
+        217: [
+          function (e, t, r) {
+            function n() {
+              (this.head = null), (this.tail = null);
+            }
+            (n.prototype = {
+              add: function (e) {
+                e = { item: e, next: null };
+                this.head ? (this.tail.next = e) : (this.head = e), (this.tail = e);
+              },
+              get: function () {
+                var e = this.head;
+                if (e) return (this.head = e.next), this.tail === e && (this.tail = null), e.item;
+              }
+            }),
+              (t.exports = n);
+          },
+          {}
+        ],
+        218: [
+          function (e, t, r) {
+            var s = e('../internals/redefine');
+            t.exports = function (e, t, r) {
+              for (var n in t) s(e, n, t[n], r);
+              return e;
+            };
+          },
+          { '../internals/redefine': 219 }
+        ],
+        219: [
+          function (e, t, r) {
+            var c = e('../internals/global'),
+              l = e('../internals/is-callable'),
+              u = e('../internals/has-own-property'),
+              p = e('../internals/create-non-enumerable-property'),
+              f = e('../internals/set-global'),
+              n = e('../internals/inspect-source'),
+              s = e('../internals/internal-state'),
+              d = e('../internals/function-name').CONFIGURABLE,
+              i = s.get,
+              h = s.enforce,
+              m = String(String).split('String');
+            (t.exports = function (e, t, r, n) {
+              var s,
+                i = !!n && !!n.unsafe,
+                o = !!n && !!n.enumerable,
+                a = !!n && !!n.noTargetGet,
+                n = n && void 0 !== n.name ? n.name : t;
+              l(r) &&
+                ('Symbol(' === String(n).slice(0, 7) && (n = '[' + String(n).replace(/^Symbol\(([^)]*)\)/, '$1') + ']'),
+                (!u(r, 'name') || (d && r.name !== n)) && p(r, 'name', n),
+                (s = h(r)).source || (s.source = m.join('string' == typeof n ? n : ''))),
+                e === c
+                  ? o
+                    ? (e[t] = r)
+                    : f(t, r)
+                  : (i ? !a && e[t] && (o = !0) : delete e[t], o ? (e[t] = r) : p(e, t, r));
+            })(Function.prototype, 'toString', function () {
+              return (l(this) && i(this).source) || n(this);
+            });
+          },
+          {
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/function-name': 153,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/inspect-source': 169,
+            '../internals/internal-state': 170,
+            '../internals/is-callable': 173,
+            '../internals/set-global': 229
+          }
+        ],
+        220: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/function-call'),
+              i = e('../internals/an-object'),
+              o = e('../internals/is-callable'),
+              a = e('../internals/classof-raw'),
+              c = e('../internals/regexp-exec'),
+              l = n.TypeError;
+            t.exports = function (e, t) {
+              var r = e.exec;
+              if (o(r)) return null !== (r = s(r, e, t)) && i(r), r;
+              if ('RegExp' === a(e)) return s(c, e, t);
+              throw l('RegExp#exec called on incompatible receiver');
+            };
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/classof-raw': 120,
+            '../internals/function-call': 152,
+            '../internals/global': 160,
+            '../internals/is-callable': 173,
+            '../internals/regexp-exec': 221
+          }
+        ],
+        221: [
+          function (e, t, r) {
+            'use strict';
+            var h = e('../internals/function-call'),
+              n = e('../internals/function-uncurry-this'),
+              m = e('../internals/to-string'),
+              y = e('../internals/regexp-flags'),
+              s = e('../internals/regexp-sticky-helpers'),
+              i = e('../internals/shared'),
+              b = e('../internals/object-create'),
+              g = e('../internals/internal-state').get,
+              o = e('../internals/regexp-unsupported-dot-all'),
+              e = e('../internals/regexp-unsupported-ncg'),
+              v = i('native-string-replace', String.prototype.replace),
+              j = RegExp.prototype.exec,
+              w = j,
+              x = n(''.charAt),
+              T = n(''.indexOf),
+              k = n(''.replace),
+              E = n(''.slice),
+              _ = ((i = /b*/g), h(j, (n = /a/), 'a'), h(j, i, 'a'), 0 !== n.lastIndex || 0 !== i.lastIndex),
+              S = s.BROKEN_CARET,
+              O = void 0 !== /()??/.exec('')[1];
+            (_ || O || S || o || e) &&
+              (w = function (e) {
+                var t,
+                  r,
+                  n,
+                  s,
+                  i,
+                  o,
+                  a = this,
+                  c = g(a),
+                  e = m(e),
+                  l = c.raw;
+                if (l) return (l.lastIndex = a.lastIndex), (p = h(w, l, e)), (a.lastIndex = l.lastIndex), p;
+                var u = c.groups,
+                  l = S && a.sticky,
+                  p = h(y, a),
+                  c = a.source,
+                  f = 0,
+                  d = e;
+                if (
+                  (l &&
+                    ((p = k(p, 'y', '')),
+                    -1 === T(p, 'g') && (p += 'g'),
+                    (d = E(e, a.lastIndex)),
+                    0 < a.lastIndex &&
+                      (!a.multiline || (a.multiline && '\n' !== x(e, a.lastIndex - 1))) &&
+                      ((c = '(?: ' + c + ')'), (d = ' ' + d), f++),
+                    (t = new RegExp('^(?:' + c + ')', p))),
+                  O && (t = new RegExp('^' + c + '$(?!\\s)', p)),
+                  _ && (r = a.lastIndex),
+                  (n = h(j, l ? t : a, d)),
+                  l
+                    ? n
+                      ? ((n.input = E(n.input, f)),
+                        (n[0] = E(n[0], f)),
+                        (n.index = a.lastIndex),
+                        (a.lastIndex += n[0].length))
+                      : (a.lastIndex = 0)
+                    : _ && n && (a.lastIndex = a.global ? n.index + n[0].length : r),
+                  O &&
+                    n &&
+                    1 < n.length &&
+                    h(v, n[0], t, function () {
+                      for (s = 1; s < arguments.length - 2; s++) void 0 === arguments[s] && (n[s] = void 0);
+                    }),
+                  n && u)
+                )
+                  for (n.groups = i = b(null), s = 0; s < u.length; s++) i[(o = u[s])[0]] = n[o[1]];
+                return n;
+              }),
+              (t.exports = w);
+          },
+          {
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/internal-state': 170,
+            '../internals/object-create': 193,
+            '../internals/regexp-flags': 222,
+            '../internals/regexp-sticky-helpers': 224,
+            '../internals/regexp-unsupported-dot-all': 225,
+            '../internals/regexp-unsupported-ncg': 226,
+            '../internals/shared': 234,
+            '../internals/to-string': 253
+          }
+        ],
+        222: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/an-object');
+            t.exports = function () {
+              var e = n(this),
+                t = '';
+              return (
+                e.hasIndices && (t += 'd'),
+                e.global && (t += 'g'),
+                e.ignoreCase && (t += 'i'),
+                e.multiline && (t += 'm'),
+                e.dotAll && (t += 's'),
+                e.unicode && (t += 'u'),
+                e.sticky && (t += 'y'),
+                t
+              );
+            };
+          },
+          { '../internals/an-object': 98 }
+        ],
+        223: [
+          function (e, t, r) {
+            var n = e('../internals/function-call'),
+              s = e('../internals/has-own-property'),
+              i = e('../internals/object-is-prototype-of'),
+              o = e('../internals/regexp-flags'),
+              a = RegExp.prototype;
+            t.exports = function (e) {
+              var t = e.flags;
+              return void 0 !== t || 'flags' in a || s(e, 'flags') || !i(a, e) ? t : n(o, e);
+            };
+          },
+          {
+            '../internals/function-call': 152,
+            '../internals/has-own-property': 161,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/regexp-flags': 222
+          }
+        ],
+        224: [
+          function (e, t, r) {
+            var n = e('../internals/fails'),
+              s = e('../internals/global').RegExp,
+              e = n(function () {
+                var e = s('a', 'y');
+                return (e.lastIndex = 2), null != e.exec('abcd');
+              }),
+              i =
+                e ||
+                n(function () {
+                  return !s('a', 'y').sticky;
+                }),
+              n =
+                e ||
+                n(function () {
+                  var e = s('^r', 'gy');
+                  return (e.lastIndex = 2), null != e.exec('str');
+                });
+            t.exports = { BROKEN_CARET: n, MISSED_STICKY: i, UNSUPPORTED_Y: e };
+          },
+          { '../internals/fails': 147, '../internals/global': 160 }
+        ],
+        225: [
+          function (e, t, r) {
+            var n = e('../internals/fails'),
+              s = e('../internals/global').RegExp;
+            t.exports = n(function () {
+              var e = s('.', 's');
+              return !(e.dotAll && e.exec('\n') && 's' === e.flags);
+            });
+          },
+          { '../internals/fails': 147, '../internals/global': 160 }
+        ],
+        226: [
+          function (e, t, r) {
+            var n = e('../internals/fails'),
+              s = e('../internals/global').RegExp;
+            t.exports = n(function () {
+              var e = s('(?<a>b)', 'g');
+              return 'b' !== e.exec('b').groups.a || 'bc' !== 'b'.replace(e, '$<a>c');
+            });
+          },
+          { '../internals/fails': 147, '../internals/global': 160 }
+        ],
+        227: [
+          function (e, t, r) {
+            var n = e('../internals/global').TypeError;
+            t.exports = function (e) {
+              if (null == e) throw n("Can't call method on " + e);
+              return e;
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        228: [
+          function (e, t, r) {
+            t.exports =
+              Object.is ||
+              function (e, t) {
+                return e === t ? 0 !== e || 1 / e == 1 / t : e != e && t != t;
+              };
+          },
+          {}
+        ],
+        229: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = Object.defineProperty;
+            t.exports = function (t, r) {
+              try {
+                s(n, t, { value: r, configurable: !0, writable: !0 });
+              } catch (e) {
+                n[t] = r;
+              }
+              return r;
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        230: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/get-built-in'),
+              s = e('../internals/object-define-property'),
+              i = e('../internals/well-known-symbol'),
+              o = e('../internals/descriptors'),
+              a = i('species');
+            t.exports = function (e) {
+              var e = n(e),
+                t = s.f;
+              o &&
+                e &&
+                !e[a] &&
+                t(e, a, {
+                  configurable: !0,
+                  get: function () {
+                    return this;
+                  }
+                });
+            };
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/get-built-in': 155,
+            '../internals/object-define-property': 195,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        231: [
+          function (e, t, r) {
+            var n = e('../internals/object-define-property').f,
+              s = e('../internals/has-own-property'),
+              i = e('../internals/well-known-symbol')('toStringTag');
+            t.exports = function (e, t, r) {
+              (e = e && !r ? e.prototype : e) && !s(e, i) && n(e, i, { configurable: !0, value: t });
+            };
+          },
+          {
+            '../internals/has-own-property': 161,
+            '../internals/object-define-property': 195,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        232: [
+          function (e, t, r) {
+            var n = e('../internals/shared'),
+              s = e('../internals/uid'),
+              i = n('keys');
+            t.exports = function (e) {
+              return i[e] || (i[e] = s(e));
+            };
+          },
+          { '../internals/shared': 234, '../internals/uid': 260 }
+        ],
+        233: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              e = e('../internals/set-global'),
+              s = '__core-js_shared__',
+              n = n[s] || e(s, {});
+            t.exports = n;
+          },
+          { '../internals/global': 160, '../internals/set-global': 229 }
+        ],
+        234: [
+          function (e, t, r) {
+            var n = e('../internals/is-pure'),
+              s = e('../internals/shared-store');
+            (t.exports = function (e, t) {
+              return s[e] || (s[e] = void 0 !== t ? t : {});
+            })('versions', []).push({
+              version: '3.22.1',
+              mode: n ? 'pure' : 'global',
+              copyright: '\xa9 2014-2022 Denis Pushkarev (zloirock.ru)',
+              license: 'https://github.com/zloirock/core-js/blob/v3.22.1/LICENSE',
+              source: 'https://github.com/zloirock/core-js'
+            });
+          },
+          { '../internals/is-pure': 178, '../internals/shared-store': 233 }
+        ],
+        235: [
+          function (e, t, r) {
+            var n = e('../internals/an-object'),
+              s = e('../internals/a-constructor'),
+              i = e('../internals/well-known-symbol')('species');
+            t.exports = function (e, t) {
+              var e = n(e).constructor;
+              return void 0 === e || null == (e = n(e)[i]) ? t : s(e);
+            };
+          },
+          { '../internals/a-constructor': 93, '../internals/an-object': 98, '../internals/well-known-symbol': 265 }
+        ],
+        236: [
+          function (e, t, r) {
+            function n(s) {
+              return function (e, t) {
+                var r,
+                  e = o(a(e)),
+                  t = i(t),
+                  n = e.length;
+                return t < 0 || n <= t
+                  ? s
+                    ? ''
+                    : void 0
+                  : (r = l(e, t)) < 55296 || 56319 < r || t + 1 === n || (n = l(e, t + 1)) < 56320 || 57343 < n
+                  ? s
+                    ? c(e, t)
+                    : r
+                  : s
+                  ? u(e, t, t + 2)
+                  : n - 56320 + ((r - 55296) << 10) + 65536;
+              };
+            }
+            var s = e('../internals/function-uncurry-this'),
+              i = e('../internals/to-integer-or-infinity'),
+              o = e('../internals/to-string'),
+              a = e('../internals/require-object-coercible'),
+              c = s(''.charAt),
+              l = s(''.charCodeAt),
+              u = s(''.slice);
+            t.exports = { codeAt: n(!1), charAt: n(!0) };
+          },
+          {
+            '../internals/function-uncurry-this': 154,
+            '../internals/require-object-coercible': 227,
+            '../internals/to-integer-or-infinity': 245,
+            '../internals/to-string': 253
+          }
+        ],
+        237: [
+          function (e, t, r) {
+            var n = e('../internals/function-name').PROPER,
+              s = e('../internals/fails'),
+              i = e('../internals/whitespaces');
+            t.exports = function (e) {
+              return s(function () {
+                return !!i[e]() || '\u200b\x85\u180e' !== '\u200b\x85\u180e'[e]() || (n && i[e].name !== e);
+              });
+            };
+          },
+          { '../internals/fails': 147, '../internals/function-name': 153, '../internals/whitespaces': 266 }
+        ],
+        238: [
+          function (e, t, r) {
+            function n(t) {
+              return function (e) {
+                e = o(i(e));
+                return 1 & t && (e = a(e, c, '')), (e = 2 & t ? a(e, l, '') : e);
+              };
+            }
+            var s = e('../internals/function-uncurry-this'),
+              i = e('../internals/require-object-coercible'),
+              o = e('../internals/to-string'),
+              e = e('../internals/whitespaces'),
+              a = s(''.replace),
+              s = '[' + e + ']',
+              c = RegExp('^' + s + s + '*'),
+              l = RegExp(s + s + '*$');
+            t.exports = { start: n(1), end: n(2), trim: n(3) };
+          },
+          {
+            '../internals/function-uncurry-this': 154,
+            '../internals/require-object-coercible': 227,
+            '../internals/to-string': 253,
+            '../internals/whitespaces': 266
+          }
+        ],
+        239: [
+          function (e, t, r) {
+            var n = e('../internals/function-call'),
+              s = e('../internals/get-built-in'),
+              i = e('../internals/well-known-symbol'),
+              o = e('../internals/redefine');
+            t.exports = function () {
+              var e = s('Symbol'),
+                e = e && e.prototype,
+                t = e && e.valueOf,
+                r = i('toPrimitive');
+              e &&
+                !e[r] &&
+                o(e, r, function (e) {
+                  return n(t, this);
+                });
+            };
+          },
+          {
+            '../internals/function-call': 152,
+            '../internals/get-built-in': 155,
+            '../internals/redefine': 219,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        240: [
+          function (e, t, r) {
+            var n,
+              s,
+              i = e('../internals/global'),
+              o = e('../internals/function-apply'),
+              a = e('../internals/function-bind-context'),
+              c = e('../internals/is-callable'),
+              l = e('../internals/has-own-property'),
+              u = e('../internals/fails'),
+              p = e('../internals/html'),
+              f = e('../internals/array-slice'),
+              d = e('../internals/document-create-element'),
+              h = e('../internals/validate-arguments-length'),
+              m = e('../internals/engine-is-ios'),
+              e = e('../internals/engine-is-node'),
+              y = i.setImmediate,
+              b = i.clearImmediate,
+              g = i.process,
+              v = i.Dispatch,
+              j = i.Function,
+              w = i.MessageChannel,
+              x = i.String,
+              T = 0,
+              k = {},
+              E = 'onreadystatechange';
+            try {
+              n = i.location;
+            } catch (e) {}
+            function _(e) {
+              return function () {
+                A(e);
+              };
+            }
+            function S(e) {
+              A(e.data);
+            }
+            function O(e) {
+              i.postMessage(x(e), n.protocol + '//' + n.host);
+            }
+            var A = function (e) {
+              var t;
+              l(k, e) && ((t = k[e]), delete k[e], t());
+            };
+            (y && b) ||
+              ((y = function (e) {
+                h(arguments.length, 1);
+                var t = c(e) ? e : j(e),
+                  r = f(arguments, 1);
+                return (
+                  (k[++T] = function () {
+                    o(t, void 0, r);
+                  }),
+                  s(T),
+                  T
+                );
+              }),
+              (b = function (e) {
+                delete k[e];
+              }),
+              e
+                ? (s = function (e) {
+                    g.nextTick(_(e));
+                  })
+                : v && v.now
+                ? (s = function (e) {
+                    v.now(_(e));
+                  })
+                : w && !m
+                ? ((m = (e = new w()).port2), (e.port1.onmessage = S), (s = a(m.postMessage, m)))
+                : i.addEventListener && c(i.postMessage) && !i.importScripts && n && 'file:' !== n.protocol && !u(O)
+                ? ((s = O), i.addEventListener('message', S, !1))
+                : (s =
+                    E in d('script')
+                      ? function (e) {
+                          p.appendChild(d('script'))[E] = function () {
+                            p.removeChild(this), A(e);
+                          };
+                        }
+                      : function (e) {
+                          setTimeout(_(e), 0);
+                        })),
+              (t.exports = { set: y, clear: b });
+          },
+          {
+            '../internals/array-slice': 114,
+            '../internals/document-create-element': 132,
+            '../internals/engine-is-ios': 139,
+            '../internals/engine-is-node': 140,
+            '../internals/fails': 147,
+            '../internals/function-apply': 149,
+            '../internals/function-bind-context': 150,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/html': 164,
+            '../internals/is-callable': 173,
+            '../internals/validate-arguments-length': 263
+          }
+        ],
+        241: [
+          function (e, t, r) {
+            e = e('../internals/function-uncurry-this');
+            t.exports = e((1).valueOf);
+          },
+          { '../internals/function-uncurry-this': 154 }
+        ],
+        242: [
+          function (e, t, r) {
+            var n = e('../internals/to-integer-or-infinity'),
+              s = Math.max,
+              i = Math.min;
+            t.exports = function (e, t) {
+              e = n(e);
+              return e < 0 ? s(e + t, 0) : i(e, t);
+            };
+          },
+          { '../internals/to-integer-or-infinity': 245 }
+        ],
+        243: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/to-integer-or-infinity'),
+              i = e('../internals/to-length'),
+              o = n.RangeError;
+            t.exports = function (e) {
+              if (void 0 === e) return 0;
+              var e = s(e),
+                t = i(e);
+              if (e !== t) throw o('Wrong length or index');
+              return t;
+            };
+          },
+          { '../internals/global': 160, '../internals/to-integer-or-infinity': 245, '../internals/to-length': 246 }
+        ],
+        244: [
+          function (e, t, r) {
+            var n = e('../internals/indexed-object'),
+              s = e('../internals/require-object-coercible');
+            t.exports = function (e) {
+              return n(s(e));
+            };
+          },
+          { '../internals/indexed-object': 167, '../internals/require-object-coercible': 227 }
+        ],
+        245: [
+          function (e, t, r) {
+            var n = Math.ceil,
+              s = Math.floor;
+            t.exports = function (e) {
+              e = +e;
+              return e != e || 0 == e ? 0 : (0 < e ? s : n)(e);
+            };
+          },
+          {}
+        ],
+        246: [
+          function (e, t, r) {
+            var n = e('../internals/to-integer-or-infinity'),
+              s = Math.min;
+            t.exports = function (e) {
+              return 0 < e ? s(n(e), 9007199254740991) : 0;
+            };
+          },
+          { '../internals/to-integer-or-infinity': 245 }
+        ],
+        247: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/require-object-coercible'),
+              i = n.Object;
+            t.exports = function (e) {
+              return i(s(e));
+            };
+          },
+          { '../internals/global': 160, '../internals/require-object-coercible': 227 }
+        ],
+        248: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/to-positive-integer'),
+              i = n.RangeError;
+            t.exports = function (e, t) {
+              e = s(e);
+              if (e % t) throw i('Wrong offset');
+              return e;
+            };
+          },
+          { '../internals/global': 160, '../internals/to-positive-integer': 249 }
+        ],
+        249: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/to-integer-or-infinity'),
+              i = n.RangeError;
+            t.exports = function (e) {
+              e = s(e);
+              if (e < 0) throw i("The argument can't be less than 0");
+              return e;
+            };
+          },
+          { '../internals/global': 160, '../internals/to-integer-or-infinity': 245 }
+        ],
+        250: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/function-call'),
+              i = e('../internals/is-object'),
+              o = e('../internals/is-symbol'),
+              a = e('../internals/get-method'),
+              c = e('../internals/ordinary-to-primitive'),
+              e = e('../internals/well-known-symbol'),
+              l = n.TypeError,
+              u = e('toPrimitive');
+            t.exports = function (e, t) {
+              if (!i(e) || o(e)) return e;
+              var r = a(e, u);
+              if (r) {
+                if (((r = s(r, e, (t = void 0 === t ? 'default' : t))), !i(r) || o(r))) return r;
+                throw l("Can't convert object to primitive value");
+              }
+              return c(e, (t = void 0 === t ? 'number' : t));
+            };
+          },
+          {
+            '../internals/function-call': 152,
+            '../internals/get-method': 158,
+            '../internals/global': 160,
+            '../internals/is-object': 177,
+            '../internals/is-symbol': 180,
+            '../internals/ordinary-to-primitive': 208,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        251: [
+          function (e, t, r) {
+            var n = e('../internals/to-primitive'),
+              s = e('../internals/is-symbol');
+            t.exports = function (e) {
+              e = n(e, 'string');
+              return s(e) ? e : e + '';
+            };
+          },
+          { '../internals/is-symbol': 180, '../internals/to-primitive': 250 }
+        ],
+        252: [
+          function (e, t, r) {
+            var n = {};
+            (n[e('../internals/well-known-symbol')('toStringTag')] = 'z'), (t.exports = '[object z]' === String(n));
+          },
+          { '../internals/well-known-symbol': 265 }
+        ],
+        253: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/classof'),
+              i = n.String;
+            t.exports = function (e) {
+              if ('Symbol' === s(e)) throw TypeError('Cannot convert a Symbol value to a string');
+              return i(e);
+            };
+          },
+          { '../internals/classof': 121, '../internals/global': 160 }
+        ],
+        254: [
+          function (e, t, r) {
+            var n = e('../internals/global').String;
+            t.exports = function (e) {
+              try {
+                return n(e);
+              } catch (e) {
+                return 'Object';
+              }
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        255: [
+          function (e, t, M) {
+            'use strict';
+            function d(e, t) {
+              re(e);
+              for (var r = 0, n = t.length, s = new e(n); r < n; ) s[r] = t[r++];
+              return s;
+            }
+            function r(e, t) {
+              _(e, t, {
+                get: function () {
+                  return E(this)[t];
+                }
+              });
+            }
+            function h(e) {
+              return z(Q, e) || 'ArrayBuffer' == (e = G(e)) || 'SharedArrayBuffer' == e;
+            }
+            function n(e, t) {
+              return N(e) && !X(t) && t in e && F(+t) && 0 <= t;
+            }
+            function s(e, t) {
+              return (t = l(t)), n(e, t) ? q(2, e[t]) : J(e, t);
+            }
+            function i(e, t, r) {
+              return (
+                (t = l(t)),
+                !(n(e, t) && w(r) && u(r, 'value')) ||
+                u(r, 'get') ||
+                u(r, 'set') ||
+                r.configurable ||
+                (u(r, 'writable') && !r.writable) ||
+                (u(r, 'enumerable') && !r.enumerable)
+                  ? _(e, t, r)
+                  : ((e[t] = r.value), e)
+              );
+            }
+            var c = e('../internals/export'),
+              m = e('../internals/global'),
+              y = e('../internals/function-call'),
+              L = e('../internals/descriptors'),
+              B = e('../internals/typed-array-constructors-require-wrappers'),
+              o = e('../internals/array-buffer-view-core'),
+              a = e('../internals/array-buffer'),
+              b = e('../internals/an-instance'),
+              q = e('../internals/create-property-descriptor'),
+              g = e('../internals/create-non-enumerable-property'),
+              F = e('../internals/is-integral-number'),
+              U = e('../internals/to-length'),
+              v = e('../internals/to-index'),
+              j = e('../internals/to-offset'),
+              l = e('../internals/to-property-key'),
+              u = e('../internals/has-own-property'),
+              G = e('../internals/classof'),
+              w = e('../internals/is-object'),
+              X = e('../internals/is-symbol'),
+              V = e('../internals/object-create'),
+              z = e('../internals/object-is-prototype-of'),
+              x = e('../internals/object-set-prototype-of'),
+              W = e('../internals/object-get-own-property-names').f,
+              T = e('../internals/typed-array-from'),
+              H = e('../internals/array-iteration').forEach,
+              K = e('../internals/set-species'),
+              p = e('../internals/object-define-property'),
+              f = e('../internals/object-get-own-property-descriptor'),
+              k = e('../internals/internal-state'),
+              Y = e('../internals/inherit-if-required'),
+              E = k.get,
+              $ = k.set,
+              _ = p.f,
+              J = f.f,
+              Z = Math.round,
+              S = m.RangeError,
+              O = a.ArrayBuffer,
+              Q = O.prototype,
+              ee = a.DataView,
+              A = o.NATIVE_ARRAY_BUFFER_VIEWS,
+              te = o.TYPED_ARRAY_CONSTRUCTOR,
+              D = o.TYPED_ARRAY_TAG,
+              I = o.TypedArray,
+              C = o.TypedArrayPrototype,
+              re = o.aTypedArrayConstructor,
+              N = o.isTypedArray,
+              R = 'BYTES_PER_ELEMENT',
+              P = 'Wrong length';
+            L
+              ? (A || ((f.f = s), (p.f = i), r(C, 'buffer'), r(C, 'byteOffset'), r(C, 'byteLength'), r(C, 'length')),
+                c({ target: 'Object', stat: !0, forced: !A }, { getOwnPropertyDescriptor: s, defineProperty: i }),
+                (t.exports = function (e, t, s) {
+                  function l(e, n) {
+                    _(e, n, {
+                      get: function () {
+                        var e = this,
+                          t = n;
+                        return (e = E(e)).view[i](t * u + e.byteOffset, !0);
+                      },
+                      set: function (e) {
+                        var t = this,
+                          r = n;
+                        (t = E(t)),
+                          s && (e = (e = Z(e)) < 0 ? 0 : 255 < e ? 255 : 255 & e),
+                          t.view[o](r * u + t.byteOffset, e, !0);
+                      },
+                      enumerable: !0
+                    });
+                  }
+                  var u = e.match(/\d+$/)[0] / 8,
+                    r = e + (s ? 'Clamped' : '') + 'Array',
+                    i = 'get' + e,
+                    o = 'set' + e,
+                    a = m[r],
+                    p = a,
+                    f = p && p.prototype,
+                    e = {};
+                  A
+                    ? B &&
+                      ((p = t(function (e, t, r, n) {
+                        return (
+                          b(e, f),
+                          Y(
+                            w(t)
+                              ? h(t)
+                                ? void 0 !== n
+                                  ? new a(t, j(r, u), n)
+                                  : void 0 !== r
+                                  ? new a(t, j(r, u))
+                                  : new a(t)
+                                : N(t)
+                                ? d(p, t)
+                                : y(T, p, t)
+                              : new a(v(t)),
+                            e,
+                            p
+                          )
+                        );
+                      })),
+                      x && x(p, I),
+                      H(W(a), function (e) {
+                        e in p || g(p, e, a[e]);
+                      }),
+                      (p.prototype = f))
+                    : ((p = t(function (e, t, r, n) {
+                        b(e, f);
+                        var s,
+                          i,
+                          o = 0,
+                          a = 0;
+                        if (w(t)) {
+                          if (!h(t)) return N(t) ? d(p, t) : y(T, p, t);
+                          var c = t,
+                            a = j(r, u),
+                            r = t.byteLength;
+                          if (void 0 === n) {
+                            if (r % u) throw S(P);
+                            if ((s = r - a) < 0) throw S(P);
+                          } else if (r < (s = U(n) * u) + a) throw S(P);
+                          i = s / u;
+                        } else (i = v(t)), (c = new O((s = i * u)));
+                        for ($(e, { buffer: c, byteOffset: a, byteLength: s, length: i, view: new ee(c) }); o < i; )
+                          l(e, o++);
+                      })),
+                      x && x(p, I),
+                      (f = p.prototype = V(C))),
+                    f.constructor !== p && g(f, 'constructor', p),
+                    g(f, te, p),
+                    D && g(f, D, r),
+                    (e[r] = p),
+                    c({ global: !0, forced: p != a, sham: !A }, e),
+                    R in p || g(p, R, u),
+                    R in f || g(f, R, u),
+                    K(r);
+                }))
+              : (t.exports = function () {});
+          },
+          {
+            '../internals/an-instance': 97,
+            '../internals/array-buffer': 101,
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-iteration': 108,
+            '../internals/classof': 121,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/create-property-descriptor': 127,
+            '../internals/descriptors': 131,
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/inherit-if-required': 168,
+            '../internals/internal-state': 170,
+            '../internals/is-integral-number': 176,
+            '../internals/is-object': 177,
+            '../internals/is-symbol': 180,
+            '../internals/object-create': 193,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/object-set-prototype-of': 205,
+            '../internals/set-species': 230,
+            '../internals/to-index': 243,
+            '../internals/to-length': 246,
+            '../internals/to-offset': 248,
+            '../internals/to-property-key': 251,
+            '../internals/typed-array-constructors-require-wrappers': 256,
+            '../internals/typed-array-from': 258
+          }
+        ],
+        256: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/fails'),
+              i = e('../internals/check-correctness-of-iteration'),
+              e = e('../internals/array-buffer-view-core').NATIVE_ARRAY_BUFFER_VIEWS,
+              o = n.ArrayBuffer,
+              a = n.Int8Array;
+            t.exports =
+              !e ||
+              !s(function () {
+                a(1);
+              }) ||
+              !s(function () {
+                new a(-1);
+              }) ||
+              !i(function (e) {
+                new a(), new a(null), new a(1.5), new a(e);
+              }, !0) ||
+              s(function () {
+                return 1 !== new a(new o(2), 1, void 0).length;
+              });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/check-correctness-of-iteration': 119,
+            '../internals/fails': 147,
+            '../internals/global': 160
+          }
+        ],
+        257: [
+          function (e, t, r) {
+            var n = e('../internals/array-from-constructor-and-list'),
+              s = e('../internals/typed-array-species-constructor');
+            t.exports = function (e, t) {
+              return n(s(e), t);
+            };
+          },
+          { '../internals/array-from-constructor-and-list': 105, '../internals/typed-array-species-constructor': 259 }
+        ],
+        258: [
+          function (e, t, r) {
+            var d = e('../internals/function-bind-context'),
+              h = e('../internals/function-call'),
+              m = e('../internals/a-constructor'),
+              y = e('../internals/to-object'),
+              b = e('../internals/length-of-array-like'),
+              g = e('../internals/get-iterator'),
+              v = e('../internals/get-iterator-method'),
+              j = e('../internals/is-array-iterator-method'),
+              w = e('../internals/array-buffer-view-core').aTypedArrayConstructor;
+            t.exports = function (e) {
+              var t,
+                r,
+                n,
+                s,
+                i,
+                o,
+                a = m(this),
+                c = y(e),
+                l = arguments.length,
+                u = 1 < l ? arguments[1] : void 0,
+                p = void 0 !== u,
+                f = v(c);
+              if (f && !j(f)) for (o = (i = g(c, f)).next, c = []; !(s = h(o, i)).done; ) c.push(s.value);
+              for (p && 2 < l && (u = d(u, arguments[2])), r = b(c), n = new (w(a))(r), t = 0; t < r; t++)
+                n[t] = p ? u(c[t], t) : c[t];
+              return n;
+            };
+          },
+          {
+            '../internals/a-constructor': 93,
+            '../internals/array-buffer-view-core': 100,
+            '../internals/function-bind-context': 150,
+            '../internals/function-call': 152,
+            '../internals/get-iterator': 157,
+            '../internals/get-iterator-method': 156,
+            '../internals/is-array-iterator-method': 171,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247
+          }
+        ],
+        259: [
+          function (e, t, r) {
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/species-constructor'),
+              i = n.TYPED_ARRAY_CONSTRUCTOR,
+              o = n.aTypedArrayConstructor;
+            t.exports = function (e) {
+              return o(s(e, e[i]));
+            };
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/species-constructor': 235 }
+        ],
+        260: [
+          function (e, t, r) {
+            var e = e('../internals/function-uncurry-this'),
+              n = 0,
+              s = Math.random(),
+              i = e((1).toString);
+            t.exports = function (e) {
+              return 'Symbol(' + (void 0 === e ? '' : e) + ')_' + i(++n + s, 36);
+            };
+          },
+          { '../internals/function-uncurry-this': 154 }
+        ],
+        261: [
+          function (e, t, r) {
+            e = e('../internals/native-symbol');
+            t.exports = e && !Symbol.sham && 'symbol' == typeof Symbol.iterator;
+          },
+          { '../internals/native-symbol': 188 }
+        ],
+        262: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              e = e('../internals/fails');
+            t.exports =
+              n &&
+              e(function () {
+                return 42 != Object.defineProperty(function () {}, 'prototype', { value: 42, writable: !1 }).prototype;
+              });
+          },
+          { '../internals/descriptors': 131, '../internals/fails': 147 }
+        ],
+        263: [
+          function (e, t, r) {
+            var n = e('../internals/global').TypeError;
+            t.exports = function (e, t) {
+              if (e < t) throw n('Not enough arguments');
+              return e;
+            };
+          },
+          { '../internals/global': 160 }
+        ],
+        264: [
+          function (e, t, r) {
+            e = e('../internals/well-known-symbol');
+            r.f = e;
+          },
+          { '../internals/well-known-symbol': 265 }
+        ],
+        265: [
+          function (e, t, r) {
+            var n = e('../internals/global'),
+              s = e('../internals/shared'),
+              i = e('../internals/has-own-property'),
+              o = e('../internals/uid'),
+              a = e('../internals/native-symbol'),
+              c = e('../internals/use-symbol-as-uid'),
+              l = s('wks'),
+              u = n.Symbol,
+              p = u && u.for,
+              f = c ? u : (u && u.withoutSetter) || o;
+            t.exports = function (e) {
+              var t;
+              return (
+                (i(l, e) && (a || 'string' == typeof l[e])) ||
+                  ((t = 'Symbol.' + e), a && i(u, e) ? (l[e] = u[e]) : (l[e] = (c && p ? p : f)(t))),
+                l[e]
+              );
+            };
+          },
+          {
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/native-symbol': 188,
+            '../internals/shared': 234,
+            '../internals/uid': 260,
+            '../internals/use-symbol-as-uid': 261
+          }
+        ],
+        266: [
+          function (e, t, r) {
+            t.exports =
+              '\t\n\v\f\r \xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff';
+          },
+          {}
+        ],
+        267: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/global'),
+              i = e('../internals/array-buffer'),
+              e = e('../internals/set-species'),
+              o = 'ArrayBuffer',
+              i = i[o];
+            n({ global: !0, forced: s[o] !== i }, { ArrayBuffer: i }), e(o);
+          },
+          {
+            '../internals/array-buffer': 101,
+            '../internals/export': 146,
+            '../internals/global': 160,
+            '../internals/set-species': 230
+          }
+        ],
+        268: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/fails'),
+              o = e('../internals/array-buffer'),
+              c = e('../internals/an-object'),
+              l = e('../internals/to-absolute-index'),
+              u = e('../internals/to-length'),
+              p = e('../internals/species-constructor'),
+              f = o.ArrayBuffer,
+              d = o.DataView,
+              e = d.prototype,
+              h = s(f.prototype.slice),
+              m = s(e.getUint8),
+              y = s(e.setUint8);
+            n(
+              {
+                target: 'ArrayBuffer',
+                proto: !0,
+                unsafe: !0,
+                forced: i(function () {
+                  return !new f(2).slice(1, void 0).byteLength;
+                })
+              },
+              {
+                slice: function (e, t) {
+                  if (h && void 0 === t) return h(c(this), e);
+                  for (
+                    var r = c(this).byteLength,
+                      n = l(e, r),
+                      s = l(void 0 === t ? r : t, r),
+                      e = new (p(this, f))(u(s - n)),
+                      i = new d(this),
+                      o = new d(e),
+                      a = 0;
+                    n < s;
+
+                  )
+                    y(o, a++, m(i, n++));
+                  return e;
+                }
+              }
+            );
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/array-buffer': 101,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/species-constructor': 235,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-length': 246
+          }
+        ],
+        269: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/global'),
+              i = e('../internals/fails'),
+              l = e('../internals/is-array'),
+              u = e('../internals/is-object'),
+              p = e('../internals/to-object'),
+              f = e('../internals/length-of-array-like'),
+              d = e('../internals/create-property'),
+              h = e('../internals/array-species-create'),
+              o = e('../internals/array-method-has-species-support'),
+              a = e('../internals/well-known-symbol'),
+              e = e('../internals/engine-v8-version'),
+              m = a('isConcatSpreadable'),
+              y = 9007199254740991,
+              b = 'Maximum allowed index exceeded',
+              g = s.TypeError,
+              a =
+                51 <= e ||
+                !i(function () {
+                  var e = [];
+                  return (e[m] = !1), e.concat()[0] !== e;
+                }),
+              s = o('concat');
+            n(
+              { target: 'Array', proto: !0, forced: !a || !s },
+              {
+                concat: function (e) {
+                  for (var t, r, n, s = p(this), i = h(s, 0), o = 0, a = -1, c = arguments.length; a < c; a++)
+                    if (
+                      (function (e) {
+                        if (!u(e)) return !1;
+                        var t = e[m];
+                        return void 0 !== t ? !!t : l(e);
+                      })((n = -1 === a ? s : arguments[a]))
+                    ) {
+                      if (((r = f(n)), y < o + r)) throw g(b);
+                      for (t = 0; t < r; t++, o++) t in n && d(i, o, n[t]);
+                    } else {
+                      if (y <= o) throw g(b);
+                      d(i, o++, n);
+                    }
+                  return (i.length = o), i;
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-method-has-species-support': 110,
+            '../internals/array-species-create': 117,
+            '../internals/create-property': 128,
+            '../internals/engine-v8-version': 143,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/global': 160,
+            '../internals/is-array': 172,
+            '../internals/is-object': 177,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        270: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/array-fill'),
+              e = e('../internals/add-to-unscopables');
+            n({ target: 'Array', proto: !0 }, { fill: s }), e('fill');
+          },
+          { '../internals/add-to-unscopables': 95, '../internals/array-fill': 103, '../internals/export': 146 }
+        ],
+        271: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/array-iteration').filter;
+            n(
+              { target: 'Array', proto: !0, forced: !e('../internals/array-method-has-species-support')('filter') },
+              {
+                filter: function (e) {
+                  return s(this, e, 1 < arguments.length ? arguments[1] : void 0);
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-iteration': 108,
+            '../internals/array-method-has-species-support': 110,
+            '../internals/export': 146
+          }
+        ],
+        272: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/array-iteration').find,
+              e = e('../internals/add-to-unscopables'),
+              i = !0;
+            'find' in [] &&
+              Array(1).find(function () {
+                i = !1;
+              }),
+              n(
+                { target: 'Array', proto: !0, forced: i },
+                {
+                  find: function (e) {
+                    return s(this, e, 1 < arguments.length ? arguments[1] : void 0);
+                  }
+                }
+              ),
+              e('find');
+          },
+          { '../internals/add-to-unscopables': 95, '../internals/array-iteration': 108, '../internals/export': 146 }
+        ],
+        273: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/array-from');
+            n(
+              {
+                target: 'Array',
+                stat: !0,
+                forced: !e('../internals/check-correctness-of-iteration')(function (e) {
+                  Array.from(e);
+                })
+              },
+              { from: s }
+            );
+          },
+          {
+            '../internals/array-from': 106,
+            '../internals/check-correctness-of-iteration': 119,
+            '../internals/export': 146
+          }
+        ],
+        274: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/array-includes').includes,
+              e = e('../internals/add-to-unscopables');
+            n(
+              { target: 'Array', proto: !0 },
+              {
+                includes: function (e) {
+                  return s(this, e, 1 < arguments.length ? arguments[1] : void 0);
+                }
+              }
+            ),
+              e('includes');
+          },
+          { '../internals/add-to-unscopables': 95, '../internals/array-includes': 107, '../internals/export': 146 }
+        ],
+        275: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/to-indexed-object'),
+              s = e('../internals/add-to-unscopables'),
+              i = e('../internals/iterators'),
+              o = e('../internals/internal-state'),
+              a = e('../internals/object-define-property').f,
+              c = e('../internals/define-iterator'),
+              l = e('../internals/is-pure'),
+              e = e('../internals/descriptors'),
+              u = 'Array Iterator',
+              p = o.set,
+              f = o.getterFor(u),
+              o =
+                ((t.exports = c(
+                  Array,
+                  'Array',
+                  function (e, t) {
+                    p(this, { type: u, target: n(e), index: 0, kind: t });
+                  },
+                  function () {
+                    var e = f(this),
+                      t = e.target,
+                      r = e.kind,
+                      n = e.index++;
+                    return !t || n >= t.length
+                      ? { value: (e.target = void 0), done: !0 }
+                      : 'keys' == r
+                      ? { value: n, done: !1 }
+                      : 'values' == r
+                      ? { value: t[n], done: !1 }
+                      : { value: [n, t[n]], done: !1 };
+                  },
+                  'values'
+                )),
+                (i.Arguments = i.Array));
+            if ((s('keys'), s('values'), s('entries'), !l && e && 'values' !== o.name))
+              try {
+                a(o, 'name', { value: 'values' });
+              } catch (e) {}
+          },
+          {
+            '../internals/add-to-unscopables': 95,
+            '../internals/define-iterator': 129,
+            '../internals/descriptors': 131,
+            '../internals/internal-state': 170,
+            '../internals/is-pure': 178,
+            '../internals/iterators': 184,
+            '../internals/object-define-property': 195,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        276: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/indexed-object'),
+              o = e('../internals/to-indexed-object'),
+              e = e('../internals/array-method-is-strict'),
+              a = s([].join),
+              s = i != Object,
+              i = e('join', ',');
+            n(
+              { target: 'Array', proto: !0, forced: s || !i },
+              {
+                join: function (e) {
+                  return a(o(this), void 0 === e ? ',' : e);
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-method-is-strict': 111,
+            '../internals/export': 146,
+            '../internals/function-uncurry-this': 154,
+            '../internals/indexed-object': 167,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        277: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/array-iteration').map;
+            n(
+              { target: 'Array', proto: !0, forced: !e('../internals/array-method-has-species-support')('map') },
+              {
+                map: function (e) {
+                  return s(this, e, 1 < arguments.length ? arguments[1] : void 0);
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-iteration': 108,
+            '../internals/array-method-has-species-support': 110,
+            '../internals/export': 146
+          }
+        ],
+        278: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/global'),
+              l = e('../internals/is-array'),
+              u = e('../internals/is-constructor'),
+              p = e('../internals/is-object'),
+              f = e('../internals/to-absolute-index'),
+              d = e('../internals/length-of-array-like'),
+              h = e('../internals/to-indexed-object'),
+              m = e('../internals/create-property'),
+              i = e('../internals/well-known-symbol'),
+              o = e('../internals/array-method-has-species-support'),
+              y = e('../internals/array-slice'),
+              e = o('slice'),
+              b = i('species'),
+              g = s.Array,
+              v = Math.max;
+            n(
+              { target: 'Array', proto: !0, forced: !e },
+              {
+                slice: function (e, t) {
+                  var r,
+                    n,
+                    s,
+                    i = h(this),
+                    o = d(i),
+                    a = f(e, o),
+                    c = f(void 0 === t ? o : t, o);
+                  if (
+                    l(i) &&
+                    ((r = i.constructor),
+                    (r = (u(r) && (r === g || l(r.prototype))) || (p(r) && null === (r = r[b])) ? void 0 : r) === g ||
+                      void 0 === r)
+                  )
+                    return y(i, a, c);
+                  for (n = new (void 0 === r ? g : r)(v(c - a, 0)), s = 0; a < c; a++, s++) a in i && m(n, s, i[a]);
+                  return (n.length = s), n;
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-method-has-species-support': 110,
+            '../internals/array-slice': 114,
+            '../internals/create-property': 128,
+            '../internals/export': 146,
+            '../internals/global': 160,
+            '../internals/is-array': 172,
+            '../internals/is-constructor': 174,
+            '../internals/is-object': 177,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-indexed-object': 244,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        279: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/function-uncurry-this'),
+              a = e('../internals/a-callable'),
+              c = e('../internals/to-object'),
+              l = e('../internals/length-of-array-like'),
+              u = e('../internals/to-string'),
+              i = e('../internals/fails'),
+              p = e('../internals/array-sort'),
+              o = e('../internals/array-method-is-strict'),
+              f = e('../internals/engine-ff-version'),
+              d = e('../internals/engine-is-ie-or-edge'),
+              h = e('../internals/engine-v8-version'),
+              m = e('../internals/engine-webkit-version'),
+              y = [],
+              b = s(y.sort),
+              g = s(y.push),
+              e = i(function () {
+                y.sort(void 0);
+              }),
+              s = i(function () {
+                y.sort(null);
+              }),
+              o = o('sort'),
+              v = !i(function () {
+                if (h) return h < 70;
+                if (!(f && 3 < f)) {
+                  if (d) return !0;
+                  if (m) return m < 603;
+                  for (var e, t, r, n = '', s = 65; s < 76; s++) {
+                    switch (((e = String.fromCharCode(s)), s)) {
+                      case 66:
+                      case 69:
+                      case 70:
+                      case 72:
+                        t = 3;
+                        break;
+                      case 68:
+                      case 71:
+                        t = 4;
+                        break;
+                      default:
+                        t = 2;
+                    }
+                    for (r = 0; r < 47; r++) y.push({ k: e + r, v: t });
+                  }
+                  for (
+                    y.sort(function (e, t) {
+                      return t.v - e.v;
+                    }),
+                      r = 0;
+                    r < y.length;
+                    r++
+                  )
+                    (e = y[r].k.charAt(0)), n.charAt(n.length - 1) !== e && (n += e);
+                  return 'DGBEFHACIJK' !== n;
+                }
+              });
+            n(
+              { target: 'Array', proto: !0, forced: e || !s || !o || !v },
+              {
+                sort: function (e) {
+                  void 0 !== e && a(e);
+                  var t = c(this);
+                  if (v) return void 0 === e ? b(t) : b(t, e);
+                  for (var r, n, s = [], i = l(t), o = 0; o < i; o++) o in t && g(s, t[o]);
+                  for (
+                    p(
+                      s,
+                      ((n = e),
+                      function (e, t) {
+                        return void 0 === t
+                          ? -1
+                          : void 0 === e
+                          ? 1
+                          : void 0 !== n
+                          ? +n(e, t) || 0
+                          : u(e) > u(t)
+                          ? 1
+                          : -1;
+                      })
+                    ),
+                      r = s.length,
+                      o = 0;
+                    o < r;
+
+                  )
+                    t[o] = s[o++];
+                  for (; o < i; ) delete t[o++];
+                  return t;
+                }
+              }
+            );
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/array-method-is-strict': 111,
+            '../internals/array-sort': 115,
+            '../internals/engine-ff-version': 135,
+            '../internals/engine-is-ie-or-edge': 137,
+            '../internals/engine-v8-version': 143,
+            '../internals/engine-webkit-version': 144,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247,
+            '../internals/to-string': 253
+          }
+        ],
+        280: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/global'),
+              p = e('../internals/to-absolute-index'),
+              f = e('../internals/to-integer-or-infinity'),
+              d = e('../internals/length-of-array-like'),
+              h = e('../internals/to-object'),
+              m = e('../internals/array-species-create'),
+              y = e('../internals/create-property'),
+              e = e('../internals/array-method-has-species-support')('splice'),
+              b = s.TypeError,
+              g = Math.max,
+              v = Math.min;
+            n(
+              { target: 'Array', proto: !0, forced: !e },
+              {
+                splice: function (e, t) {
+                  var r,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c = h(this),
+                    l = d(c),
+                    u = p(e, l),
+                    e = arguments.length;
+                  if (
+                    (0 === e ? (r = n = 0) : (n = 1 === e ? ((r = 0), l - u) : ((r = e - 2), v(g(f(t), 0), l - u))),
+                    9007199254740991 < l + r - n)
+                  )
+                    throw b('Maximum allowed length exceeded');
+                  for (s = m(c, n), i = 0; i < n; i++) (o = u + i) in c && y(s, i, c[o]);
+                  if (r < (s.length = n)) {
+                    for (i = u; i < l - n; i++) (a = i + r), (o = i + n) in c ? (c[a] = c[o]) : delete c[a];
+                    for (i = l; l - n + r < i; i--) delete c[i - 1];
+                  } else if (n < r)
+                    for (i = l - n; u < i; i--) (a = i + r - 1), (o = i + n - 1) in c ? (c[a] = c[o]) : delete c[a];
+                  for (i = 0; i < r; i++) c[i + u] = arguments[i + 2];
+                  return (c.length = l - n + r), s;
+                }
+              }
+            );
+          },
+          {
+            '../internals/array-method-has-species-support': 110,
+            '../internals/array-species-create': 117,
+            '../internals/create-property': 128,
+            '../internals/export': 146,
+            '../internals/global': 160,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-integer-or-infinity': 245,
+            '../internals/to-object': 247
+          }
+        ],
+        281: [
+          function (e, t, r) {
+            var n = e('../internals/descriptors'),
+              s = e('../internals/function-name').EXISTS,
+              i = e('../internals/function-uncurry-this'),
+              e = e('../internals/object-define-property').f,
+              o = Function.prototype,
+              a = i(o.toString),
+              c = /function\b(?:\s|\/\*[\S\s]*?\*\/|\/\/[^\n\r]*[\n\r]+)*([^\s(/]*)/,
+              l = i(c.exec);
+            n &&
+              !s &&
+              e(o, 'name', {
+                configurable: !0,
+                get: function () {
+                  try {
+                    return l(c, a(this))[1];
+                  } catch (e) {
+                    return '';
+                  }
+                }
+              });
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/function-name': 153,
+            '../internals/function-uncurry-this': 154,
+            '../internals/object-define-property': 195
+          }
+        ],
+        282: [
+          function (e, t, r) {
+            function s(e, t) {
+              var r = m(arguments),
+                n = t;
+              if ((d(t) || void 0 !== e) && !h(e))
+                return (
+                  p(t) ||
+                    (t = function (e, t) {
+                      if ((f(n) && (t = c(n, this, e, t)), !h(t))) return t;
+                    }),
+                  (r[1] = t),
+                  a(y, null, r)
+                );
+            }
+            function i(e, t, r) {
+              var n = g(r, t - 1),
+                r = g(r, t + 1);
+              return (b(T, e) && !b(k, r)) || (b(k, e) && !b(T, n)) ? '\\u' + w(v(e, 0), 16) : e;
+            }
+            var n = e('../internals/export'),
+              o = e('../internals/get-built-in'),
+              a = e('../internals/function-apply'),
+              c = e('../internals/function-call'),
+              l = e('../internals/function-uncurry-this'),
+              u = e('../internals/fails'),
+              p = e('../internals/is-array'),
+              f = e('../internals/is-callable'),
+              d = e('../internals/is-object'),
+              h = e('../internals/is-symbol'),
+              m = e('../internals/array-slice'),
+              e = e('../internals/native-symbol'),
+              y = o('JSON', 'stringify'),
+              b = l(/./.exec),
+              g = l(''.charAt),
+              v = l(''.charCodeAt),
+              j = l(''.replace),
+              w = l((1).toString),
+              x = /[\uD800-\uDFFF]/g,
+              T = /^[\uD800-\uDBFF]$/,
+              k = /^[\uDC00-\uDFFF]$/,
+              E =
+                !e ||
+                u(function () {
+                  var e = o('Symbol')();
+                  return '[null]' != y([e]) || '{}' != y({ a: e }) || '{}' != y(Object(e));
+                }),
+              _ = u(function () {
+                return '"\\udf06\\ud834"' !== y('\udf06\ud834') || '"\\udead"' !== y('\udead');
+              });
+            y &&
+              n(
+                { target: 'JSON', stat: !0, forced: E || _ },
+                {
+                  stringify: function (e, t, r) {
+                    var n = m(arguments),
+                      n = a(E ? s : y, null, n);
+                    return _ && 'string' == typeof n ? j(n, x, i) : n;
+                  }
+                }
+              );
+          },
+          {
+            '../internals/array-slice': 114,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/function-apply': 149,
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/get-built-in': 155,
+            '../internals/is-array': 172,
+            '../internals/is-callable': 173,
+            '../internals/is-object': 177,
+            '../internals/is-symbol': 180,
+            '../internals/native-symbol': 188
+          }
+        ],
+        283: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/descriptors'),
+              s = e('../internals/global'),
+              i = e('../internals/function-uncurry-this'),
+              o = e('../internals/is-forced'),
+              a = e('../internals/redefine'),
+              c = e('../internals/has-own-property'),
+              l = e('../internals/inherit-if-required'),
+              u = e('../internals/object-is-prototype-of'),
+              p = e('../internals/is-symbol'),
+              f = e('../internals/to-primitive'),
+              d = e('../internals/fails'),
+              h = e('../internals/object-get-own-property-names').f,
+              m = e('../internals/object-get-own-property-descriptor').f,
+              y = e('../internals/object-define-property').f,
+              b = e('../internals/this-number-value'),
+              g = e('../internals/string-trim').trim,
+              e = 'Number',
+              v = s[e],
+              j = v.prototype,
+              w = s.TypeError,
+              x = i(''.slice),
+              T = i(''.charCodeAt),
+              k = function (e) {
+                var t,
+                  r,
+                  n,
+                  s,
+                  i,
+                  o,
+                  a,
+                  c = f(e, 'number');
+                if (p(c)) throw w('Cannot convert a Symbol value to a number');
+                if ('string' == typeof c && 2 < c.length)
+                  if (((c = g(c)), 43 === (e = T(c, 0)) || 45 === e)) {
+                    if (88 === (t = T(c, 2)) || 120 === t) return NaN;
+                  } else if (48 === e) {
+                    switch (T(c, 1)) {
+                      case 66:
+                      case 98:
+                        (r = 2), (n = 49);
+                        break;
+                      case 79:
+                      case 111:
+                        (r = 8), (n = 55);
+                        break;
+                      default:
+                        return +c;
+                    }
+                    for (i = (s = x(c, 2)).length, o = 0; o < i; o++) if ((a = T(s, o)) < 48 || n < a) return NaN;
+                    return parseInt(s, r);
+                  }
+                return +c;
+              };
+            if (o(e, !v(' 0o1') || !v('0b1') || v('+0x1'))) {
+              for (
+                var E,
+                  _ = function (e) {
+                    var e =
+                        arguments.length < 1
+                          ? 0
+                          : v(
+                              (function (e) {
+                                e = f(e, 'number');
+                                return 'bigint' == typeof e ? e : k(e);
+                              })(e)
+                            ),
+                      t = this;
+                    return u(j, t) &&
+                      d(function () {
+                        b(t);
+                      })
+                      ? l(Object(e), t, _)
+                      : e;
+                  },
+                  S = n
+                    ? h(v)
+                    : 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range'.split(
+                        ','
+                      ),
+                  O = 0;
+                S.length > O;
+                O++
+              )
+                c(v, (E = S[O])) && !c(_, E) && y(_, E, m(v, E));
+              a(s, e, ((_.prototype = j).constructor = _));
+            }
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/inherit-if-required': 168,
+            '../internals/is-forced': 175,
+            '../internals/is-symbol': 180,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/redefine': 219,
+            '../internals/string-trim': 238,
+            '../internals/this-number-value': 241,
+            '../internals/to-primitive': 250
+          }
+        ],
+        284: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              e = e('../internals/object-assign');
+            n({ target: 'Object', stat: !0, forced: Object.assign !== e }, { assign: e });
+          },
+          { '../internals/export': 146, '../internals/object-assign': 192 }
+        ],
+        285: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/object-to-array').entries;
+            n(
+              { target: 'Object', stat: !0 },
+              {
+                entries: function (e) {
+                  return s(e);
+                }
+              }
+            );
+          },
+          { '../internals/export': 146, '../internals/object-to-array': 206 }
+        ],
+        286: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/fails'),
+              i = e('../internals/to-indexed-object'),
+              o = e('../internals/object-get-own-property-descriptor').f,
+              e = e('../internals/descriptors'),
+              s = s(function () {
+                o(1);
+              });
+            n(
+              { target: 'Object', stat: !0, forced: !e || s, sham: !e },
+              {
+                getOwnPropertyDescriptor: function (e, t) {
+                  return o(i(e), t);
+                }
+              }
+            );
+          },
+          {
+            '../internals/descriptors': 131,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        287: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/descriptors'),
+              c = e('../internals/own-keys'),
+              l = e('../internals/to-indexed-object'),
+              u = e('../internals/object-get-own-property-descriptor'),
+              p = e('../internals/create-property');
+            n(
+              { target: 'Object', stat: !0, sham: !s },
+              {
+                getOwnPropertyDescriptors: function (e) {
+                  for (var t, r, n = l(e), s = u.f, i = c(n), o = {}, a = 0; i.length > a; )
+                    void 0 !== (r = s(n, (t = i[a++]))) && p(o, t, r);
+                  return o;
+                }
+              }
+            );
+          },
+          {
+            '../internals/create-property': 128,
+            '../internals/descriptors': 131,
+            '../internals/export': 146,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/own-keys': 209,
+            '../internals/to-indexed-object': 244
+          }
+        ],
+        288: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/native-symbol'),
+              i = e('../internals/fails'),
+              o = e('../internals/object-get-own-property-symbols'),
+              a = e('../internals/to-object');
+            n(
+              {
+                target: 'Object',
+                stat: !0,
+                forced:
+                  !s ||
+                  i(function () {
+                    o.f(1);
+                  })
+              },
+              {
+                getOwnPropertySymbols: function (e) {
+                  var t = o.f;
+                  return t ? t(a(e)) : [];
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/native-symbol': 188,
+            '../internals/object-get-own-property-symbols': 199,
+            '../internals/to-object': 247
+          }
+        ],
+        289: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/to-object'),
+              i = e('../internals/object-keys');
+            n(
+              {
+                target: 'Object',
+                stat: !0,
+                forced: e('../internals/fails')(function () {
+                  i(1);
+                })
+              },
+              {
+                keys: function (e) {
+                  return i(s(e));
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/object-keys': 203,
+            '../internals/to-object': 247
+          }
+        ],
+        290: [
+          function (e, t, r) {
+            var n = e('../internals/to-string-tag-support'),
+              s = e('../internals/redefine'),
+              e = e('../internals/object-to-string');
+            n || s(Object.prototype, 'toString', e, { unsafe: !0 });
+          },
+          {
+            '../internals/object-to-string': 207,
+            '../internals/redefine': 219,
+            '../internals/to-string-tag-support': 252
+          }
+        ],
+        291: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              u = e('../internals/function-call'),
+              p = e('../internals/a-callable'),
+              s = e('../internals/new-promise-capability'),
+              i = e('../internals/perform'),
+              f = e('../internals/iterate');
+            n(
+              { target: 'Promise', stat: !0, forced: e('../internals/promise-statics-incorrect-iteration') },
+              {
+                all: function (e) {
+                  var a = this,
+                    t = s.f(a),
+                    c = t.resolve,
+                    l = t.reject,
+                    r = i(function () {
+                      var n = p(a.resolve),
+                        s = [],
+                        i = 0,
+                        o = 1;
+                      f(e, function (e) {
+                        var t = i++,
+                          r = !1;
+                        o++,
+                          u(n, a, e).then(function (e) {
+                            r || ((r = !0), (s[t] = e), --o || c(s));
+                          }, l);
+                      }),
+                        --o || c(s);
+                    });
+                  return r.error && l(r.value), t.promise;
+                }
+              }
+            );
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/iterate': 181,
+            '../internals/new-promise-capability': 190,
+            '../internals/perform': 211,
+            '../internals/promise-statics-incorrect-iteration': 215
+          }
+        ],
+        292: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/is-pure'),
+              i = e('../internals/promise-constructor-detection').CONSTRUCTOR,
+              o = e('../internals/promise-native-constructor'),
+              a = e('../internals/get-built-in'),
+              c = e('../internals/is-callable'),
+              e = e('../internals/redefine'),
+              l = o && o.prototype;
+            n(
+              { target: 'Promise', proto: !0, forced: i, real: !0 },
+              {
+                catch: function (e) {
+                  return this.then(void 0, e);
+                }
+              }
+            ),
+              !s && c(o) && ((n = a('Promise').prototype.catch), l.catch !== n && e(l, 'catch', n, { unsafe: !0 }));
+          },
+          {
+            '../internals/export': 146,
+            '../internals/get-built-in': 155,
+            '../internals/is-callable': 173,
+            '../internals/is-pure': 178,
+            '../internals/promise-constructor-detection': 212,
+            '../internals/promise-native-constructor': 213,
+            '../internals/redefine': 219
+          }
+        ],
+        293: [
+          function (e, M, L) {
+            'use strict';
+            function i(e, t) {
+              var r,
+                n,
+                s,
+                i,
+                o = t.value,
+                a = t.state == _,
+                c = a ? e.ok : e.fail,
+                l = e.resolve,
+                u = e.reject,
+                p = e.domain;
+              try {
+                c
+                  ? (a ||
+                      (t.rejection === O &&
+                        ((i = t),
+                        h(m, d, function () {
+                          var e = i.facade;
+                          f ? T.emit('rejectionHandled', e) : I(ee, e, i.value);
+                        })),
+                      (t.rejection = S)),
+                    !0 === c ? (r = o) : (p && p.enter(), (r = c(o)), p && (p.exit(), (s = !0))),
+                    r === e.promise ? u(w('Promise-chain cycle')) : (n = A(r)) ? h(n, r, l, u) : l(r))
+                  : u(o);
+              } catch (e) {
+                p && !s && p.exit(), u(e);
+              }
+            }
+            var r,
+              t,
+              n,
+              s = e('../internals/export'),
+              B = e('../internals/is-pure'),
+              f = e('../internals/engine-is-node'),
+              d = e('../internals/global'),
+              h = e('../internals/function-call'),
+              q = e('../internals/redefine'),
+              F = e('../internals/redefine-all'),
+              o = e('../internals/object-set-prototype-of'),
+              U = e('../internals/set-to-string-tag'),
+              G = e('../internals/set-species'),
+              X = e('../internals/a-callable'),
+              a = e('../internals/is-callable'),
+              V = e('../internals/is-object'),
+              z = e('../internals/an-instance'),
+              W = e('../internals/species-constructor'),
+              m = e('../internals/task').set,
+              c = e('../internals/microtask'),
+              H = e('../internals/host-report-errors'),
+              K = e('../internals/perform'),
+              Y = e('../internals/queue'),
+              l = e('../internals/internal-state'),
+              u = e('../internals/promise-native-constructor'),
+              p = e('../internals/promise-constructor-detection'),
+              e = e('../internals/new-promise-capability'),
+              y = 'Promise',
+              b = p.CONSTRUCTOR,
+              $ = p.REJECTION_EVENT,
+              p = p.SUBCLASSING,
+              g = l.getterFor(y),
+              J = l.set,
+              l = u && u.prototype,
+              v = u,
+              j = l,
+              w = d.TypeError,
+              x = d.document,
+              T = d.process,
+              k = e.f,
+              Z = k,
+              Q = !!(x && x.createEvent && d.dispatchEvent),
+              E = 'unhandledrejection',
+              ee = 'rejectionhandled',
+              _ = 1,
+              te = 2,
+              S = 1,
+              O = 2,
+              A = function (e) {
+                var t;
+                return !(!V(e) || !a((t = e.then))) && t;
+              },
+              D = function (r, s) {
+                r.notified ||
+                  ((r.notified = !0),
+                  c(function () {
+                    for (var e, n, t = r.reactions; (e = t.get()); ) i(e, r);
+                    (r.notified = !1),
+                      s &&
+                        !r.rejection &&
+                        ((n = r),
+                        h(m, d, function () {
+                          var e = n.facade,
+                            t = n.value,
+                            r = C(n);
+                          if (
+                            r &&
+                            ((r = K(function () {
+                              f ? T.emit('unhandledRejection', t, e) : I(E, e, t);
+                            })),
+                            (n.rejection = f || C(n) ? O : S),
+                            r.error)
+                          )
+                            throw r.value;
+                        }));
+                  }));
+              },
+              I = function (e, t, r) {
+                var n;
+                Q
+                  ? (((n = x.createEvent('Event')).promise = t),
+                    (n.reason = r),
+                    n.initEvent(e, !1, !0),
+                    d.dispatchEvent(n))
+                  : (n = { promise: t, reason: r }),
+                  !$ && (t = d['on' + e]) ? t(n) : e === E && H('Unhandled promise rejection', r);
+              },
+              C = function (e) {
+                return e.rejection !== S && !e.parent;
+              },
+              N = function (t, r, n) {
+                return function (e) {
+                  t(r, e, n);
+                };
+              },
+              R = function (e, t, r) {
+                e.done || ((e.done = !0), ((e = r ? r : e).value = t), (e.state = te), D(e, !0));
+              },
+              P = function (r, e, t) {
+                if (!r.done) {
+                  (r.done = !0), t && (r = t);
+                  try {
+                    if (r.facade === e) throw w("Promise can't be resolved itself");
+                    var n = A(e);
+                    n
+                      ? c(function () {
+                          var t = { done: !1 };
+                          try {
+                            h(n, e, N(P, t, r), N(R, t, r));
+                          } catch (e) {
+                            R(t, e, r);
+                          }
+                        })
+                      : ((r.value = e), (r.state = _), D(r, !1));
+                  } catch (e) {
+                    R({ done: !1 }, e, r);
+                  }
+                }
+              };
+            if (
+              b &&
+              ((j = (v = function (e) {
+                z(this, j), X(e), h(r, this);
+                var t = g(this);
+                try {
+                  e(N(P, t), N(R, t));
+                } catch (e) {
+                  R(t, e);
+                }
+              }).prototype),
+              ((r = function (e) {
+                J(this, {
+                  type: y,
+                  done: !1,
+                  notified: !1,
+                  parent: !1,
+                  reactions: new Y(),
+                  rejection: !1,
+                  state: 0,
+                  value: void 0
+                });
+              }).prototype = F(j, {
+                then: function (e, t) {
+                  var r = g(this),
+                    n = k(W(this, v));
+                  return (
+                    (r.parent = !0),
+                    (n.ok = !a(e) || e),
+                    (n.fail = a(t) && t),
+                    (n.domain = f ? T.domain : void 0),
+                    0 == r.state
+                      ? r.reactions.add(n)
+                      : c(function () {
+                          i(n, r);
+                        }),
+                    n.promise
+                  );
+                }
+              })),
+              (t = function () {
+                var e = new r(),
+                  t = g(e);
+                (this.promise = e), (this.resolve = N(P, t)), (this.reject = N(R, t));
+              }),
+              (e.f = k =
+                function (e) {
+                  return e === v || void 0 === e ? new t() : Z(e);
+                }),
+              !B && a(u) && l !== Object.prototype)
+            ) {
+              (n = l.then),
+                p ||
+                  q(
+                    l,
+                    'then',
+                    function (e, t) {
+                      var r = this;
+                      return new v(function (e, t) {
+                        h(n, r, e, t);
+                      }).then(e, t);
+                    },
+                    { unsafe: !0 }
+                  );
+              try {
+                delete l.constructor;
+              } catch (e) {}
+              o && o(l, j);
+            }
+            s({ global: !0, wrap: !0, forced: b }, { Promise: v }), U(v, y, !1, !0), G(y);
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/an-instance': 97,
+            '../internals/engine-is-node': 140,
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/global': 160,
+            '../internals/host-report-errors': 163,
+            '../internals/internal-state': 170,
+            '../internals/is-callable': 173,
+            '../internals/is-object': 177,
+            '../internals/is-pure': 178,
+            '../internals/microtask': 186,
+            '../internals/new-promise-capability': 190,
+            '../internals/object-set-prototype-of': 205,
+            '../internals/perform': 211,
+            '../internals/promise-constructor-detection': 212,
+            '../internals/promise-native-constructor': 213,
+            '../internals/queue': 217,
+            '../internals/redefine': 219,
+            '../internals/redefine-all': 218,
+            '../internals/set-species': 230,
+            '../internals/set-to-string-tag': 231,
+            '../internals/species-constructor': 235,
+            '../internals/task': 240
+          }
+        ],
+        294: [
+          function (e, t, r) {
+            e('../modules/es.promise.constructor'),
+              e('../modules/es.promise.all'),
+              e('../modules/es.promise.catch'),
+              e('../modules/es.promise.race'),
+              e('../modules/es.promise.reject'),
+              e('../modules/es.promise.resolve');
+          },
+          {
+            '../modules/es.promise.all': 291,
+            '../modules/es.promise.catch': 292,
+            '../modules/es.promise.constructor': 293,
+            '../modules/es.promise.race': 295,
+            '../modules/es.promise.reject': 296,
+            '../modules/es.promise.resolve': 297
+          }
+        ],
+        295: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              i = e('../internals/function-call'),
+              o = e('../internals/a-callable'),
+              a = e('../internals/new-promise-capability'),
+              c = e('../internals/perform'),
+              l = e('../internals/iterate');
+            n(
+              { target: 'Promise', stat: !0, forced: e('../internals/promise-statics-incorrect-iteration') },
+              {
+                race: function (e) {
+                  var r = this,
+                    n = a.f(r),
+                    s = n.reject,
+                    t = c(function () {
+                      var t = o(r.resolve);
+                      l(e, function (e) {
+                        i(t, r, e).then(n.resolve, s);
+                      });
+                    });
+                  return t.error && s(t.value), n.promise;
+                }
+              }
+            );
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/iterate': 181,
+            '../internals/new-promise-capability': 190,
+            '../internals/perform': 211,
+            '../internals/promise-statics-incorrect-iteration': 215
+          }
+        ],
+        296: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/function-call'),
+              i = e('../internals/new-promise-capability');
+            n(
+              { target: 'Promise', stat: !0, forced: e('../internals/promise-constructor-detection').CONSTRUCTOR },
+              {
+                reject: function (e) {
+                  var t = i.f(this);
+                  return s(t.reject, void 0, e), t.promise;
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/function-call': 152,
+            '../internals/new-promise-capability': 190,
+            '../internals/promise-constructor-detection': 212
+          }
+        ],
+        297: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/get-built-in'),
+              i = e('../internals/is-pure'),
+              o = e('../internals/promise-native-constructor'),
+              a = e('../internals/promise-constructor-detection').CONSTRUCTOR,
+              c = e('../internals/promise-resolve'),
+              l = s('Promise'),
+              u = i && !a;
+            n(
+              { target: 'Promise', stat: !0, forced: i || a },
+              {
+                resolve: function (e) {
+                  return c(u && this === l ? o : this, e);
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/get-built-in': 155,
+            '../internals/is-pure': 178,
+            '../internals/promise-constructor-detection': 212,
+            '../internals/promise-native-constructor': 213,
+            '../internals/promise-resolve': 214
+          }
+        ],
+        298: [
+          function (e, M, L) {
+            var t = e('../internals/descriptors'),
+              r = e('../internals/global'),
+              n = e('../internals/function-uncurry-this'),
+              s = e('../internals/is-forced'),
+              l = e('../internals/inherit-if-required'),
+              u = e('../internals/create-non-enumerable-property'),
+              i = e('../internals/object-get-own-property-names').f,
+              p = e('../internals/object-is-prototype-of'),
+              f = e('../internals/is-regexp'),
+              d = e('../internals/to-string'),
+              h = e('../internals/regexp-get-flags'),
+              o = e('../internals/regexp-sticky-helpers'),
+              a = e('../internals/proxy-accessor'),
+              c = e('../internals/redefine'),
+              m = e('../internals/fails'),
+              y = e('../internals/has-own-property'),
+              b = e('../internals/internal-state').enforce,
+              g = e('../internals/set-species'),
+              v = e('../internals/well-known-symbol'),
+              j = e('../internals/regexp-unsupported-dot-all'),
+              w = e('../internals/regexp-unsupported-ncg'),
+              x = v('match'),
+              T = r.RegExp,
+              k = T.prototype,
+              E = r.SyntaxError,
+              _ = n(k.exec),
+              S = n(''.charAt),
+              O = n(''.replace),
+              A = n(''.indexOf),
+              B = n(''.slice),
+              q = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,
+              D = /a/g,
+              I = /a/g,
+              e = new T(D) !== D,
+              C = o.MISSED_STICKY,
+              F = o.UNSUPPORTED_Y,
+              v =
+                t &&
+                (!e ||
+                  C ||
+                  j ||
+                  w ||
+                  m(function () {
+                    return (I[x] = !1), T(D) != D || T(I) == I || '/a/i' != T(D, 'i');
+                  }));
+            if (s('RegExp', v)) {
+              function N(e, t) {
+                var r,
+                  n,
+                  s = p(k, this),
+                  i = f(e),
+                  o = void 0 === t,
+                  a = [],
+                  c = e;
+                if (!s && i && o && e.constructor === N) return e;
+                if (
+                  ((i || p(k, e)) && ((e = e.source), o && (t = h(c))),
+                  (e = void 0 === e ? '' : d(e)),
+                  (t = void 0 === t ? '' : d(t)),
+                  (c = e),
+                  (i = t = j && 'dotAll' in D && (r = !!t && -1 < A(t, 's')) ? O(t, /s/g, '') : t),
+                  C && 'sticky' in D && (n = !!t && -1 < A(t, 'y')) && F && (t = O(t, /y/g, '')),
+                  w &&
+                    ((e = (o = (function (e) {
+                      for (
+                        var t, r = e.length, n = 0, s = '', i = [], o = {}, a = !1, c = !1, l = 0, u = '';
+                        n <= r;
+                        n++
+                      ) {
+                        if ('\\' === (t = S(e, n))) t += S(e, ++n);
+                        else if (']' === t) a = !1;
+                        else if (!a)
+                          switch (!0) {
+                            case '[' === t:
+                              a = !0;
+                              break;
+                            case '(' === t:
+                              _(q, B(e, n + 1)) && ((n += 2), (c = !0)), (s += t), l++;
+                              continue;
+                            case '>' === t && c:
+                              if ('' === u || y(o, u)) throw new E('Invalid capture group name');
+                              (o[u] = !0), (c = !(i[i.length] = [u, l])), (u = '');
+                              continue;
+                          }
+                        c ? (u += t) : (s += t);
+                      }
+                      return [s, i];
+                    })(e))[0]),
+                    (a = o[1])),
+                  (o = l(T(e, t), s ? this : k, N)),
+                  (r || n || a.length) &&
+                    ((t = b(o)),
+                    r &&
+                      ((t.dotAll = !0),
+                      (t.raw = N(
+                        (function (e) {
+                          for (var t, r = e.length, n = 0, s = '', i = !1; n <= r; n++)
+                            '\\' === (t = S(e, n))
+                              ? (s += t + S(e, ++n))
+                              : i || '.' !== t
+                              ? ('[' === t ? (i = !0) : ']' === t && (i = !1), (s += t))
+                              : (s += '[\\s\\S]');
+                          return s;
+                        })(e),
+                        i
+                      ))),
+                    n && (t.sticky = !0),
+                    a.length && (t.groups = a)),
+                  e !== c)
+                )
+                  try {
+                    u(o, 'source', '' === c ? '(?:)' : c);
+                  } catch (e) {}
+                return o;
+              }
+              for (var R = i(T), P = 0; R.length > P; ) a(N, T, R[P++]);
+              ((k.constructor = N).prototype = k), c(r, 'RegExp', N);
+            }
+            g('RegExp');
+          },
+          {
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/descriptors': 131,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/inherit-if-required': 168,
+            '../internals/internal-state': 170,
+            '../internals/is-forced': 175,
+            '../internals/is-regexp': 179,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/proxy-accessor': 216,
+            '../internals/redefine': 219,
+            '../internals/regexp-get-flags': 223,
+            '../internals/regexp-sticky-helpers': 224,
+            '../internals/regexp-unsupported-dot-all': 225,
+            '../internals/regexp-unsupported-ncg': 226,
+            '../internals/set-species': 230,
+            '../internals/to-string': 253,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        299: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              e = e('../internals/regexp-exec');
+            n({ target: 'RegExp', proto: !0, forced: /./.exec !== e }, { exec: e });
+          },
+          { '../internals/export': 146, '../internals/regexp-exec': 221 }
+        ],
+        300: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/function-name').PROPER,
+              s = e('../internals/redefine'),
+              i = e('../internals/an-object'),
+              o = e('../internals/to-string'),
+              a = e('../internals/fails'),
+              c = e('../internals/regexp-get-flags'),
+              e = 'toString',
+              l = RegExp.prototype[e],
+              a = a(function () {
+                return '/a/b' != l.call({ source: 'a', flags: 'b' });
+              }),
+              n = n && l.name != e;
+            (a || n) &&
+              s(
+                RegExp.prototype,
+                e,
+                function () {
+                  var e = i(this);
+                  return '/' + o(e.source) + '/' + o(c(e));
+                },
+                { unsafe: !0 }
+              );
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/fails': 147,
+            '../internals/function-name': 153,
+            '../internals/redefine': 219,
+            '../internals/regexp-get-flags': 223,
+            '../internals/to-string': 253
+          }
+        ],
+        301: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/not-a-regexp'),
+              o = e('../internals/require-object-coercible'),
+              a = e('../internals/to-string'),
+              e = e('../internals/correct-is-regexp-logic'),
+              c = s(''.indexOf);
+            n(
+              { target: 'String', proto: !0, forced: !e('includes') },
+              {
+                includes: function (e) {
+                  return !!~c(a(o(this)), a(i(e)), 1 < arguments.length ? arguments[1] : void 0);
+                }
+              }
+            );
+          },
+          {
+            '../internals/correct-is-regexp-logic': 123,
+            '../internals/export': 146,
+            '../internals/function-uncurry-this': 154,
+            '../internals/not-a-regexp': 191,
+            '../internals/require-object-coercible': 227,
+            '../internals/to-string': 253
+          }
+        ],
+        302: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/string-multibyte').charAt,
+              s = e('../internals/to-string'),
+              i = e('../internals/internal-state'),
+              e = e('../internals/define-iterator'),
+              o = 'String Iterator',
+              a = i.set,
+              c = i.getterFor(o);
+            e(
+              String,
+              'String',
+              function (e) {
+                a(this, { type: o, string: s(e), index: 0 });
+              },
+              function () {
+                var e = c(this),
+                  t = e.string,
+                  r = e.index;
+                return r >= t.length
+                  ? { value: void 0, done: !0 }
+                  : ((t = n(t, r)), (e.index += t.length), { value: t, done: !1 });
+              }
+            );
+          },
+          {
+            '../internals/define-iterator': 129,
+            '../internals/internal-state': 170,
+            '../internals/string-multibyte': 236,
+            '../internals/to-string': 253
+          }
+        ],
+        303: [
+          function (e, t, r) {
+            'use strict';
+            var s = e('../internals/function-call'),
+              n = e('../internals/fix-regexp-well-known-symbol-logic'),
+              l = e('../internals/an-object'),
+              u = e('../internals/to-length'),
+              p = e('../internals/to-string'),
+              i = e('../internals/require-object-coercible'),
+              o = e('../internals/get-method'),
+              f = e('../internals/advance-string-index'),
+              d = e('../internals/regexp-exec-abstract');
+            n('match', function (n, a, c) {
+              return [
+                function (e) {
+                  var t = i(this),
+                    r = null == e ? void 0 : o(e, n);
+                  return r ? s(r, e, t) : new RegExp(e)[n](p(t));
+                },
+                function (e) {
+                  var t = l(this),
+                    r = p(e),
+                    e = c(a, t, r);
+                  if (e.done) return e.value;
+                  if (!t.global) return d(t, r);
+                  for (var n = t.unicode, s = [], i = (t.lastIndex = 0); null !== (o = d(t, r)); ) {
+                    var o = p(o[0]);
+                    '' === (s[i] = o) && (t.lastIndex = f(r, u(t.lastIndex), n)), i++;
+                  }
+                  return 0 === i ? null : s;
+                }
+              ];
+            });
+          },
+          {
+            '../internals/advance-string-index': 96,
+            '../internals/an-object': 98,
+            '../internals/fix-regexp-well-known-symbol-logic': 148,
+            '../internals/function-call': 152,
+            '../internals/get-method': 158,
+            '../internals/regexp-exec-abstract': 220,
+            '../internals/require-object-coercible': 227,
+            '../internals/to-length': 246,
+            '../internals/to-string': 253
+          }
+        ],
+        304: [
+          function (e, t, r) {
+            'use strict';
+            var x = e('../internals/function-apply'),
+              s = e('../internals/function-call'),
+              n = e('../internals/function-uncurry-this'),
+              i = e('../internals/fix-regexp-well-known-symbol-logic'),
+              o = e('../internals/fails'),
+              T = e('../internals/an-object'),
+              k = e('../internals/is-callable'),
+              E = e('../internals/to-integer-or-infinity'),
+              _ = e('../internals/to-length'),
+              S = e('../internals/to-string'),
+              a = e('../internals/require-object-coercible'),
+              O = e('../internals/advance-string-index'),
+              c = e('../internals/get-method'),
+              A = e('../internals/get-substitution'),
+              D = e('../internals/regexp-exec-abstract'),
+              l = e('../internals/well-known-symbol')('replace'),
+              I = Math.max,
+              C = Math.min,
+              N = n([].concat),
+              R = n([].push),
+              P = n(''.indexOf),
+              M = n(''.slice),
+              e = '$0' === 'a'.replace(/./, '$0'),
+              u = !!/./[l] && '' === /./[l]('a', '$0');
+            i(
+              'replace',
+              function (e, v, j) {
+                var w = u ? '$' : '$0';
+                return [
+                  function (e, t) {
+                    var r = a(this),
+                      n = null == e ? void 0 : c(e, l);
+                    return n ? s(n, e, r, t) : s(v, S(r), e, t);
+                  },
+                  function (e, t) {
+                    var r = T(this),
+                      n = S(e);
+                    if ('string' == typeof t && -1 === P(t, w) && -1 === P(t, '$<')) {
+                      e = j(v, r, n, t);
+                      if (e.done) return e.value;
+                    }
+                    for (
+                      var s,
+                        i = k(t),
+                        o = (i || (t = S(t)), r.global),
+                        a = (o && ((s = r.unicode), (r.lastIndex = 0)), []);
+                      null !== (f = D(r, n)) && (R(a, f), o);
+
+                    )
+                      '' === S(f[0]) && (r.lastIndex = O(n, _(r.lastIndex), s));
+                    for (var c, l = '', u = 0, p = 0; p < a.length; p++) {
+                      for (
+                        var f, d = S((f = a[p])[0]), h = I(C(E(f.index), n.length), 0), m = [], y = 1;
+                        y < f.length;
+                        y++
+                      )
+                        R(m, void 0 === (c = f[y]) ? c : String(c));
+                      var b = f.groups,
+                        g = i
+                          ? ((g = N([d], m, h, n)), void 0 !== b && R(g, b), S(x(t, void 0, g)))
+                          : A(d, n, h, m, b, t);
+                      u <= h && ((l += M(n, u, h) + g), (u = h + d.length));
+                    }
+                    return l + M(n, u);
+                  }
+                ];
+              },
+              !!o(function () {
+                var e = /./;
+                return (
+                  (e.exec = function () {
+                    var e = [];
+                    return (e.groups = { a: '7' }), e;
+                  }),
+                  '7' !== ''.replace(e, '$<a>')
+                );
+              }) ||
+                !e ||
+                u
+            );
+          },
+          {
+            '../internals/advance-string-index': 96,
+            '../internals/an-object': 98,
+            '../internals/fails': 147,
+            '../internals/fix-regexp-well-known-symbol-logic': 148,
+            '../internals/function-apply': 149,
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/get-method': 158,
+            '../internals/get-substitution': 159,
+            '../internals/is-callable': 173,
+            '../internals/regexp-exec-abstract': 220,
+            '../internals/require-object-coercible': 227,
+            '../internals/to-integer-or-infinity': 245,
+            '../internals/to-length': 246,
+            '../internals/to-string': 253,
+            '../internals/well-known-symbol': 265
+          }
+        ],
+        305: [
+          function (e, t, r) {
+            'use strict';
+            var o = e('../internals/function-call'),
+              n = e('../internals/fix-regexp-well-known-symbol-logic'),
+              a = e('../internals/an-object'),
+              c = e('../internals/require-object-coercible'),
+              l = e('../internals/same-value'),
+              u = e('../internals/to-string'),
+              p = e('../internals/get-method'),
+              f = e('../internals/regexp-exec-abstract');
+            n('search', function (n, s, i) {
+              return [
+                function (e) {
+                  var t = c(this),
+                    r = null == e ? void 0 : p(e, n);
+                  return r ? o(r, e, t) : new RegExp(e)[n](u(t));
+                },
+                function (e) {
+                  var t = a(this),
+                    e = u(e),
+                    r = i(s, t, e);
+                  if (r.done) return r.value;
+                  (r = t.lastIndex), l(r, 0) || (t.lastIndex = 0), (e = f(t, e));
+                  return l(t.lastIndex, r) || (t.lastIndex = r), null === e ? -1 : e.index;
+                }
+              ];
+            });
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/fix-regexp-well-known-symbol-logic': 148,
+            '../internals/function-call': 152,
+            '../internals/get-method': 158,
+            '../internals/regexp-exec-abstract': 220,
+            '../internals/require-object-coercible': 227,
+            '../internals/same-value': 228,
+            '../internals/to-string': 253
+          }
+        ],
+        306: [
+          function (e, t, r) {
+            'use strict';
+            var u = e('../internals/function-apply'),
+              p = e('../internals/function-call'),
+              n = e('../internals/function-uncurry-this'),
+              s = e('../internals/fix-regexp-well-known-symbol-logic'),
+              f = e('../internals/is-regexp'),
+              b = e('../internals/an-object'),
+              d = e('../internals/require-object-coercible'),
+              g = e('../internals/species-constructor'),
+              v = e('../internals/advance-string-index'),
+              j = e('../internals/to-length'),
+              w = e('../internals/to-string'),
+              i = e('../internals/get-method'),
+              x = e('../internals/array-slice-simple'),
+              T = e('../internals/regexp-exec-abstract'),
+              k = e('../internals/regexp-exec'),
+              o = e('../internals/regexp-sticky-helpers'),
+              e = e('../internals/fails'),
+              E = o.UNSUPPORTED_Y,
+              _ = Math.min,
+              S = [].push,
+              O = n(/./.exec),
+              A = n(S),
+              D = n(''.slice);
+            s(
+              'split',
+              function (s, h, m) {
+                var y =
+                  'c' == 'abbc'.split(/(b)*/)[1] ||
+                  4 != 'test'.split(/(?:)/, -1).length ||
+                  2 != 'ab'.split(/(?:ab)*/).length ||
+                  4 != '.'.split(/(.?)(.?)/).length ||
+                  1 < '.'.split(/()()/).length ||
+                  ''.split(/.?/).length
+                    ? function (e, t) {
+                        var r = w(d(this)),
+                          n = void 0 === t ? 4294967295 : t >>> 0;
+                        if (0 == n) return [];
+                        if (void 0 === e) return [r];
+                        if (!f(e)) return p(h, r, e, n);
+                        for (
+                          var s,
+                            i,
+                            o,
+                            a = [],
+                            t =
+                              (e.ignoreCase ? 'i' : '') +
+                              (e.multiline ? 'm' : '') +
+                              (e.unicode ? 'u' : '') +
+                              (e.sticky ? 'y' : ''),
+                            c = 0,
+                            l = new RegExp(e.source, t + 'g');
+                          (s = p(k, l, r)) &&
+                          !(
+                            c < (i = l.lastIndex) &&
+                            (A(a, D(r, c, s.index)),
+                            1 < s.length && s.index < r.length && u(S, a, x(s, 1)),
+                            (o = s[0].length),
+                            (c = i),
+                            n <= a.length)
+                          );
+
+                        )
+                          l.lastIndex === s.index && l.lastIndex++;
+                        return (
+                          c === r.length ? (!o && O(l, '')) || A(a, '') : A(a, D(r, c)), n < a.length ? x(a, 0, n) : a
+                        );
+                      }
+                    : '0'.split(void 0, 0).length
+                    ? function (e, t) {
+                        return void 0 === e && 0 === t ? [] : p(h, this, e, t);
+                      }
+                    : h;
+                return [
+                  function (e, t) {
+                    var r = d(this),
+                      n = null == e ? void 0 : i(e, s);
+                    return n ? p(n, e, r, t) : p(y, w(r), e, t);
+                  },
+                  function (e, t) {
+                    var r = b(this),
+                      n = w(e),
+                      e = m(y, r, n, t, y !== h);
+                    if (e.done) return e.value;
+                    var e = g(r, RegExp),
+                      s = r.unicode,
+                      i =
+                        (r.ignoreCase ? 'i' : '') + (r.multiline ? 'm' : '') + (r.unicode ? 'u' : '') + (E ? 'g' : 'y'),
+                      o = new e(E ? '^(?:' + r.source + ')' : r, i),
+                      a = void 0 === t ? 4294967295 : t >>> 0;
+                    if (0 == a) return [];
+                    if (0 === n.length) return null === T(o, n) ? [n] : [];
+                    for (var c = 0, l = 0, u = []; l < n.length; ) {
+                      o.lastIndex = E ? 0 : l;
+                      var p,
+                        f = T(o, E ? D(n, l) : n);
+                      if (null === f || (p = _(j(o.lastIndex + (E ? l : 0)), n.length)) === c) l = v(n, l, s);
+                      else {
+                        if ((A(u, D(n, c, l)), u.length === a)) return u;
+                        for (var d = 1; d <= f.length - 1; d++) if ((A(u, f[d]), u.length === a)) return u;
+                        l = c = p;
+                      }
+                    }
+                    return A(u, D(n, c)), u;
+                  }
+                ];
+              },
+              !!e(function () {
+                var e = /(?:)/,
+                  t = e.exec,
+                  e =
+                    ((e.exec = function () {
+                      return t.apply(this, arguments);
+                    }),
+                    'ab'.split(e));
+                return 2 !== e.length || 'a' !== e[0] || 'b' !== e[1];
+              }),
+              E
+            );
+          },
+          {
+            '../internals/advance-string-index': 96,
+            '../internals/an-object': 98,
+            '../internals/array-slice-simple': 113,
+            '../internals/fails': 147,
+            '../internals/fix-regexp-well-known-symbol-logic': 148,
+            '../internals/function-apply': 149,
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/get-method': 158,
+            '../internals/is-regexp': 179,
+            '../internals/regexp-exec': 221,
+            '../internals/regexp-exec-abstract': 220,
+            '../internals/regexp-sticky-helpers': 224,
+            '../internals/require-object-coercible': 227,
+            '../internals/species-constructor': 235,
+            '../internals/to-length': 246,
+            '../internals/to-string': 253
+          }
+        ],
+        307: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/export'),
+              s = e('../internals/string-trim').trim;
+            n(
+              { target: 'String', proto: !0, forced: e('../internals/string-trim-forced')('trim') },
+              {
+                trim: function () {
+                  return s(this);
+                }
+              }
+            );
+          },
+          { '../internals/export': 146, '../internals/string-trim': 238, '../internals/string-trim-forced': 237 }
+        ],
+        308: [
+          function (e, M, L) {
+            'use strict';
+            function n(e, t) {
+              var r = (C[e] = g(D));
+              return te(r, { type: O, tag: e, description: t }), p || (r.description = t), r;
+            }
+            function s(e, t, r) {
+              return (
+                e === A && s(N, t, r),
+                h(e),
+                (t = y(t)),
+                h(r),
+                d(C, t)
+                  ? (r.enumerable
+                      ? (d(e, S) && e[S][t] && (e[S][t] = !1), (r = g(r, { enumerable: b(0, !1) })))
+                      : (d(e, S) || I(e, S, b(1, {})), (e[S][t] = !0)),
+                    P(e, t, r))
+                  : I(e, t, r)
+              );
+            }
+            function r(t, e) {
+              h(t);
+              var r = m(e),
+                e = v(r).concat(a(r));
+              return (
+                _(e, function (e) {
+                  (p && !u(i, r, e)) || s(t, e, r[e]);
+                }),
+                t
+              );
+            }
+            function i(e) {
+              var e = y(e),
+                t = u(oe, this, e);
+              return (
+                !(this === A && d(C, e) && !d(N, e)) &&
+                (!(t || !d(this, e) || !d(C, e) || (d(this, S) && this[S][e])) || t)
+              );
+            }
+            function t(e, t) {
+              var r,
+                e = m(e),
+                t = y(t);
+              if (e !== A || !d(C, t) || d(N, t))
+                return !(r = se(e, t)) || !d(C, t) || (d(e, S) && e[S][t]) || (r.enumerable = !0), r;
+            }
+            function o(e) {
+              var e = ie(m(e)),
+                t = [];
+              return (
+                _(e, function (e) {
+                  d(C, e) || d(K, e) || ae(t, e);
+                }),
+                t
+              );
+            }
+            function a(e) {
+              var t = e === A,
+                e = ie(t ? N : m(e)),
+                r = [];
+              return (
+                _(e, function (e) {
+                  !d(C, e) || (t && !d(A, e)) || ae(r, C[e]);
+                }),
+                r
+              );
+            }
+            var c = e('../internals/export'),
+              l = e('../internals/global'),
+              u = e('../internals/function-call'),
+              B = e('../internals/function-uncurry-this'),
+              q = e('../internals/is-pure'),
+              p = e('../internals/descriptors'),
+              f = e('../internals/native-symbol'),
+              F = e('../internals/fails'),
+              d = e('../internals/has-own-property'),
+              U = e('../internals/object-is-prototype-of'),
+              h = e('../internals/an-object'),
+              m = e('../internals/to-indexed-object'),
+              y = e('../internals/to-property-key'),
+              G = e('../internals/to-string'),
+              b = e('../internals/create-property-descriptor'),
+              g = e('../internals/object-create'),
+              v = e('../internals/object-keys'),
+              X = e('../internals/object-get-own-property-names'),
+              j = e('../internals/object-get-own-property-names-external'),
+              V = e('../internals/object-get-own-property-symbols'),
+              w = e('../internals/object-get-own-property-descriptor'),
+              z = e('../internals/object-define-property'),
+              W = e('../internals/object-define-properties'),
+              H = e('../internals/object-property-is-enumerable'),
+              x = e('../internals/redefine'),
+              T = e('../internals/shared'),
+              k = e('../internals/shared-key'),
+              K = e('../internals/hidden-keys'),
+              Y = e('../internals/uid'),
+              $ = e('../internals/well-known-symbol'),
+              J = e('../internals/well-known-symbol-wrapped'),
+              Z = e('../internals/define-well-known-symbol'),
+              Q = e('../internals/symbol-define-to-primitive'),
+              ee = e('../internals/set-to-string-tag'),
+              E = e('../internals/internal-state'),
+              _ = e('../internals/array-iteration').forEach,
+              S = k('hidden'),
+              O = 'Symbol',
+              e = 'prototype',
+              te = E.set,
+              re = E.getterFor(O),
+              A = Object[e],
+              k = l.Symbol,
+              D = k && k[e],
+              ne = l.TypeError,
+              E = l.QObject,
+              se = w.f,
+              I = z.f,
+              ie = j.f,
+              oe = H.f,
+              ae = B([].push),
+              C = T('symbols'),
+              N = T('op-symbols'),
+              l = T('wks'),
+              R = !E || !E[e] || !E[e].findChild,
+              P =
+                p &&
+                F(function () {
+                  return (
+                    7 !=
+                    g(
+                      I({}, 'a', {
+                        get: function () {
+                          return I(this, 'a', { value: 7 }).a;
+                        }
+                      })
+                    ).a
+                  );
+                })
+                  ? function (e, t, r) {
+                      var n = se(A, t);
+                      n && delete A[t], I(e, t, r), n && e !== A && I(A, t, n);
+                    }
+                  : I;
+            f ||
+              (x(
+                (D = (k = function () {
+                  if (U(D, this)) throw ne('Symbol is not a constructor');
+                  var e = arguments.length && void 0 !== arguments[0] ? G(arguments[0]) : void 0,
+                    t = Y(e),
+                    r = function (e) {
+                      this === A && u(r, N, e), d(this, S) && d(this[S], t) && (this[S][t] = !1), P(this, t, b(1, e));
+                    };
+                  return p && R && P(A, t, { configurable: !0, set: r }), n(t, e);
+                })[e]),
+                'toString',
+                function () {
+                  return re(this).tag;
+                }
+              ),
+              x(k, 'withoutSetter', function (e) {
+                return n(Y(e), e);
+              }),
+              (H.f = i),
+              (z.f = s),
+              (W.f = r),
+              (w.f = t),
+              (X.f = j.f = o),
+              (V.f = a),
+              (J.f = function (e) {
+                return n($(e), e);
+              }),
+              p &&
+                (I(D, 'description', {
+                  configurable: !0,
+                  get: function () {
+                    return re(this).description;
+                  }
+                }),
+                q || x(A, 'propertyIsEnumerable', i, { unsafe: !0 }))),
+              c({ global: !0, wrap: !0, forced: !f, sham: !f }, { Symbol: k }),
+              _(v(l), function (e) {
+                Z(e);
+              }),
+              c(
+                { target: O, stat: !0, forced: !f },
+                {
+                  useSetter: function () {
+                    R = !0;
+                  },
+                  useSimple: function () {
+                    R = !1;
+                  }
+                }
+              ),
+              c(
+                { target: 'Object', stat: !0, forced: !f, sham: !p },
+                {
+                  create: function (e, t) {
+                    return void 0 === t ? g(e) : r(g(e), t);
+                  },
+                  defineProperty: s,
+                  defineProperties: r,
+                  getOwnPropertyDescriptor: t
+                }
+              ),
+              c({ target: 'Object', stat: !0, forced: !f }, { getOwnPropertyNames: o }),
+              Q(),
+              ee(k, O),
+              (K[S] = !0);
+          },
+          {
+            '../internals/an-object': 98,
+            '../internals/array-iteration': 108,
+            '../internals/create-property-descriptor': 127,
+            '../internals/define-well-known-symbol': 130,
+            '../internals/descriptors': 131,
+            '../internals/export': 146,
+            '../internals/fails': 147,
+            '../internals/function-call': 152,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/hidden-keys': 162,
+            '../internals/internal-state': 170,
+            '../internals/is-pure': 178,
+            '../internals/native-symbol': 188,
+            '../internals/object-create': 193,
+            '../internals/object-define-properties': 194,
+            '../internals/object-define-property': 195,
+            '../internals/object-get-own-property-descriptor': 196,
+            '../internals/object-get-own-property-names': 198,
+            '../internals/object-get-own-property-names-external': 197,
+            '../internals/object-get-own-property-symbols': 199,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/object-keys': 203,
+            '../internals/object-property-is-enumerable': 204,
+            '../internals/redefine': 219,
+            '../internals/set-to-string-tag': 231,
+            '../internals/shared': 234,
+            '../internals/shared-key': 232,
+            '../internals/symbol-define-to-primitive': 239,
+            '../internals/to-indexed-object': 244,
+            '../internals/to-property-key': 251,
+            '../internals/to-string': 253,
+            '../internals/uid': 260,
+            '../internals/well-known-symbol': 265,
+            '../internals/well-known-symbol-wrapped': 264
+          }
+        ],
+        309: [
+          function (e, t, r) {
+            'use strict';
+            var n,
+              s,
+              i,
+              o,
+              a,
+              c,
+              l,
+              u = e('../internals/export'),
+              p = e('../internals/descriptors'),
+              f = e('../internals/global'),
+              d = e('../internals/function-uncurry-this'),
+              h = e('../internals/has-own-property'),
+              m = e('../internals/is-callable'),
+              y = e('../internals/object-is-prototype-of'),
+              b = e('../internals/to-string'),
+              g = e('../internals/object-define-property').f,
+              e = e('../internals/copy-constructor-properties'),
+              v = f.Symbol,
+              j = v && v.prototype;
+            !p ||
+              !m(v) ||
+              ('description' in j && void 0 === v().description) ||
+              ((n = {}),
+              e(
+                (f = function () {
+                  var e = arguments.length < 1 || void 0 === arguments[0] ? void 0 : b(arguments[0]),
+                    t = y(j, this) ? new v(e) : void 0 === e ? v() : v(e);
+                  return '' === e && (n[t] = !0), t;
+                }),
+                v
+              ),
+              ((f.prototype = j).constructor = f),
+              (s = 'Symbol(test)' == String(v('test'))),
+              (i = d(j.toString)),
+              (o = d(j.valueOf)),
+              (a = /^Symbol\((.*)\)[^)]+$/),
+              (c = d(''.replace)),
+              (l = d(''.slice)),
+              g(j, 'description', {
+                configurable: !0,
+                get: function () {
+                  var e = o(this),
+                    t = i(e);
+                  if (h(n, e)) return '';
+                  e = s ? l(t, 7, -1) : c(t, a, '$1');
+                  return '' === e ? void 0 : e;
+                }
+              }),
+              u({ global: !0, forced: !0 }, { Symbol: f }));
+          },
+          {
+            '../internals/copy-constructor-properties': 122,
+            '../internals/descriptors': 131,
+            '../internals/export': 146,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/has-own-property': 161,
+            '../internals/is-callable': 173,
+            '../internals/object-define-property': 195,
+            '../internals/object-is-prototype-of': 201,
+            '../internals/to-string': 253
+          }
+        ],
+        310: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/get-built-in'),
+              i = e('../internals/has-own-property'),
+              o = e('../internals/to-string'),
+              a = e('../internals/shared'),
+              e = e('../internals/native-symbol-registry'),
+              c = a('string-to-symbol-registry'),
+              l = a('symbol-to-string-registry');
+            n(
+              { target: 'Symbol', stat: !0, forced: !e },
+              {
+                for: function (e) {
+                  e = o(e);
+                  if (i(c, e)) return c[e];
+                  var t = s('Symbol')(e);
+                  return (c[e] = t), (l[t] = e), t;
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/get-built-in': 155,
+            '../internals/has-own-property': 161,
+            '../internals/native-symbol-registry': 187,
+            '../internals/shared': 234,
+            '../internals/to-string': 253
+          }
+        ],
+        311: [
+          function (e, t, r) {
+            e('../internals/define-well-known-symbol')('iterator');
+          },
+          { '../internals/define-well-known-symbol': 130 }
+        ],
+        312: [
+          function (e, t, r) {
+            e('../modules/es.symbol.constructor'),
+              e('../modules/es.symbol.for'),
+              e('../modules/es.symbol.key-for'),
+              e('../modules/es.json.stringify'),
+              e('../modules/es.object.get-own-property-symbols');
+          },
+          {
+            '../modules/es.json.stringify': 282,
+            '../modules/es.object.get-own-property-symbols': 288,
+            '../modules/es.symbol.constructor': 308,
+            '../modules/es.symbol.for': 310,
+            '../modules/es.symbol.key-for': 313
+          }
+        ],
+        313: [
+          function (e, t, r) {
+            var n = e('../internals/export'),
+              s = e('../internals/has-own-property'),
+              i = e('../internals/is-symbol'),
+              o = e('../internals/try-to-string'),
+              a = e('../internals/shared'),
+              e = e('../internals/native-symbol-registry'),
+              c = a('symbol-to-string-registry');
+            n(
+              { target: 'Symbol', stat: !0, forced: !e },
+              {
+                keyFor: function (e) {
+                  if (!i(e)) throw TypeError(o(e) + ' is not a symbol');
+                  if (s(c, e)) return c[e];
+                }
+              }
+            );
+          },
+          {
+            '../internals/export': 146,
+            '../internals/has-own-property': 161,
+            '../internals/is-symbol': 180,
+            '../internals/native-symbol-registry': 187,
+            '../internals/shared': 234,
+            '../internals/try-to-string': 254
+          }
+        ],
+        314: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/function-uncurry-this'),
+              s = e('../internals/array-buffer-view-core'),
+              i = n(e('../internals/array-copy-within')),
+              o = s.aTypedArray;
+            (0, s.exportTypedArrayMethod)('copyWithin', function (e, t) {
+              return i(o(this), e, t, 2 < arguments.length ? arguments[2] : void 0);
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-copy-within': 102,
+            '../internals/function-uncurry-this': 154
+          }
+        ],
+        315: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').every,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('every', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-iteration': 108 }
+        ],
+        316: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/function-call'),
+              i = e('../internals/array-fill'),
+              o = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('fill', function (e) {
+              var t = arguments.length;
+              return s(i, o(this), e, 1 < t ? arguments[1] : void 0, 2 < t ? arguments[2] : void 0);
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-fill': 103,
+            '../internals/function-call': 152
+          }
+        ],
+        317: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').filter,
+              i = e('../internals/typed-array-from-species-and-list'),
+              o = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('filter', function (e) {
+              e = s(o(this), e, 1 < arguments.length ? arguments[1] : void 0);
+              return i(this, e);
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-iteration': 108,
+            '../internals/typed-array-from-species-and-list': 257
+          }
+        ],
+        318: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').findIndex,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('findIndex', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-iteration': 108 }
+        ],
+        319: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').find,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('find', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-iteration': 108 }
+        ],
+        320: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').forEach,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('forEach', function (e) {
+              s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-iteration': 108 }
+        ],
+        321: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-includes').includes,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('includes', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-includes': 107 }
+        ],
+        322: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-includes').indexOf,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('indexOf', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-includes': 107 }
+        ],
+        323: [
+          function (e, t, r) {
+            'use strict';
+            function n() {
+              return u(d(this));
+            }
+            var s = e('../internals/global'),
+              i = e('../internals/fails'),
+              o = e('../internals/function-uncurry-this'),
+              a = e('../internals/array-buffer-view-core'),
+              c = e('../modules/es.array.iterator'),
+              l = e('../internals/well-known-symbol')('iterator'),
+              e = s.Uint8Array,
+              u = o(c.values),
+              p = o(c.keys),
+              f = o(c.entries),
+              d = a.aTypedArray,
+              s = a.exportTypedArrayMethod,
+              h = e && e.prototype,
+              o = !i(function () {
+                h[l].call([1]);
+              }),
+              c = !!h && h.values && h[l] === h.values && 'values' === h.values.name;
+            s(
+              'entries',
+              function () {
+                return f(d(this));
+              },
+              o
+            ),
+              s(
+                'keys',
+                function () {
+                  return p(d(this));
+                },
+                o
+              ),
+              s('values', n, o || !c, { name: 'values' }),
+              s(l, n, o || !c, { name: 'values' });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160,
+            '../internals/well-known-symbol': 265,
+            '../modules/es.array.iterator': 275
+          }
+        ],
+        324: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              e = e('../internals/function-uncurry-this'),
+              s = n.aTypedArray,
+              n = n.exportTypedArrayMethod,
+              i = e([].join);
+            n('join', function (e) {
+              return i(s(this), e);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/function-uncurry-this': 154 }
+        ],
+        325: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/function-apply'),
+              i = e('../internals/array-last-index-of'),
+              o = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('lastIndexOf', function (e) {
+              var t = arguments.length;
+              return s(i, o(this), 1 < t ? [e, arguments[1]] : [e]);
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-last-index-of': 109,
+            '../internals/function-apply': 149
+          }
+        ],
+        326: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').map,
+              i = e('../internals/typed-array-species-constructor'),
+              o = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('map', function (e) {
+              return s(o(this), e, 1 < arguments.length ? arguments[1] : void 0, function (e, t) {
+                return new (i(e))(t);
+              });
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-iteration': 108,
+            '../internals/typed-array-species-constructor': 259
+          }
+        ],
+        327: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-reduce').right,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('reduceRight', function (e) {
+              var t = arguments.length;
+              return s(i(this), e, t, 1 < t ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-reduce': 112 }
+        ],
+        328: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-reduce').left,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('reduce', function (e) {
+              var t = arguments.length;
+              return s(i(this), e, t, 1 < t ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-reduce': 112 }
+        ],
+        329: [
+          function (e, t, r) {
+            'use strict';
+            var e = e('../internals/array-buffer-view-core'),
+              s = e.aTypedArray,
+              e = e.exportTypedArrayMethod,
+              i = Math.floor;
+            e('reverse', function () {
+              for (var e, t = s(this).length, r = i(t / 2), n = 0; n < r; )
+                (e = this[n]), (this[n++] = this[--t]), (this[t] = e);
+              return this;
+            });
+          },
+          { '../internals/array-buffer-view-core': 100 }
+        ],
+        330: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/global'),
+              i = e('../internals/function-call'),
+              s = e('../internals/array-buffer-view-core'),
+              o = e('../internals/length-of-array-like'),
+              a = e('../internals/to-offset'),
+              c = e('../internals/to-object'),
+              e = e('../internals/fails'),
+              l = n.RangeError,
+              u = n.Int8Array,
+              n = u && u.prototype,
+              p = n && n.set,
+              f = s.aTypedArray,
+              n = s.exportTypedArrayMethod,
+              d = !e(function () {
+                var e = new Uint8ClampedArray(2);
+                return i(p, e, { length: 1, 0: 3 }, 1), 3 !== e[1];
+              }),
+              s =
+                d &&
+                s.NATIVE_ARRAY_BUFFER_VIEWS &&
+                e(function () {
+                  var e = new u(2);
+                  return e.set(1), e.set('2', 1), 0 !== e[0] || 2 !== e[1];
+                });
+            n(
+              'set',
+              function (e) {
+                f(this);
+                var t = a(1 < arguments.length ? arguments[1] : void 0, 1),
+                  r = c(e);
+                if (d) return i(p, this, r, t);
+                var e = this.length,
+                  n = o(r),
+                  s = 0;
+                if (e < n + t) throw l('Wrong length');
+                for (; s < n; ) this[t + s] = r[s++];
+              },
+              !d || s
+            );
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/fails': 147,
+            '../internals/function-call': 152,
+            '../internals/global': 160,
+            '../internals/length-of-array-like': 185,
+            '../internals/to-object': 247,
+            '../internals/to-offset': 248
+          }
+        ],
+        331: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              o = e('../internals/typed-array-species-constructor'),
+              s = e('../internals/fails'),
+              a = e('../internals/array-slice'),
+              c = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)(
+              'slice',
+              function (e, t) {
+                for (var r = a(c(this), e, t), e = o(this), n = 0, s = r.length, i = new e(s); n < s; ) i[n] = r[n++];
+                return i;
+              },
+              s(function () {
+                new Int8Array(1).slice();
+              })
+            );
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-slice': 114,
+            '../internals/fails': 147,
+            '../internals/typed-array-species-constructor': 259
+          }
+        ],
+        332: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/array-iteration').some,
+              i = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('some', function (e) {
+              return s(i(this), e, 1 < arguments.length ? arguments[1] : void 0);
+            });
+          },
+          { '../internals/array-buffer-view-core': 100, '../internals/array-iteration': 108 }
+        ],
+        333: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/global'),
+              s = e('../internals/function-uncurry-this'),
+              i = e('../internals/fails'),
+              o = e('../internals/a-callable'),
+              a = e('../internals/array-sort'),
+              c = e('../internals/array-buffer-view-core'),
+              l = e('../internals/engine-ff-version'),
+              u = e('../internals/engine-is-ie-or-edge'),
+              p = e('../internals/engine-v8-version'),
+              f = e('../internals/engine-webkit-version'),
+              d = c.aTypedArray,
+              e = c.exportTypedArrayMethod,
+              h = n.Uint16Array,
+              m = h && s(h.prototype.sort),
+              c = !(
+                !m ||
+                (i(function () {
+                  m(new h(2), null);
+                }) &&
+                  i(function () {
+                    m(new h(2), {});
+                  }))
+              ),
+              y =
+                !!m &&
+                !i(function () {
+                  if (p) return p < 74;
+                  if (l) return l < 67;
+                  if (u) return !0;
+                  if (f) return f < 602;
+                  for (var e, t = new h(516), r = Array(516), n = 0; n < 516; n++)
+                    (e = n % 4), (t[n] = 515 - n), (r[n] = n - 2 * e + 3);
+                  for (
+                    m(t, function (e, t) {
+                      return ((e / 4) | 0) - ((t / 4) | 0);
+                    }),
+                      n = 0;
+                    n < 516;
+                    n++
+                  )
+                    if (t[n] !== r[n]) return !0;
+                });
+            e(
+              'sort',
+              function (e) {
+                return (
+                  void 0 !== e && o(e),
+                  y
+                    ? m(this, e)
+                    : a(
+                        d(this),
+                        ((r = e),
+                        function (e, t) {
+                          return void 0 !== r
+                            ? +r(e, t) || 0
+                            : t != t
+                            ? -1
+                            : e != e
+                            ? 1
+                            : 0 === e && 0 === t
+                            ? 0 < 1 / e && 1 / t < 0
+                              ? 1
+                              : -1
+                            : t < e;
+                        })
+                      )
+                );
+                var r;
+              },
+              !y || c
+            );
+          },
+          {
+            '../internals/a-callable': 92,
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-sort': 115,
+            '../internals/engine-ff-version': 135,
+            '../internals/engine-is-ie-or-edge': 137,
+            '../internals/engine-v8-version': 143,
+            '../internals/engine-webkit-version': 144,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160
+          }
+        ],
+        334: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core'),
+              s = e('../internals/to-length'),
+              i = e('../internals/to-absolute-index'),
+              o = e('../internals/typed-array-species-constructor'),
+              a = n.aTypedArray;
+            (0, n.exportTypedArrayMethod)('subarray', function (e, t) {
+              var r = a(this),
+                n = r.length,
+                e = i(e, n);
+              return new (o(r))(r.buffer, r.byteOffset + e * r.BYTES_PER_ELEMENT, s((void 0 === t ? n : i(t, n)) - e));
+            });
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/to-absolute-index': 242,
+            '../internals/to-length': 246,
+            '../internals/typed-array-species-constructor': 259
+          }
+        ],
+        335: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/global'),
+              s = e('../internals/function-apply'),
+              i = e('../internals/array-buffer-view-core'),
+              o = e('../internals/fails'),
+              a = e('../internals/array-slice'),
+              c = n.Int8Array,
+              l = i.aTypedArray,
+              e = i.exportTypedArrayMethod,
+              u = [].toLocaleString,
+              p =
+                !!c &&
+                o(function () {
+                  u.call(new c(1));
+                });
+            e(
+              'toLocaleString',
+              function () {
+                return s(u, p ? a(l(this)) : l(this), a(arguments));
+              },
+              o(function () {
+                return [1, 2].toLocaleString() != new c([1, 2]).toLocaleString();
+              }) ||
+                !o(function () {
+                  c.prototype.toLocaleString.call([1, 2]);
+                })
+            );
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/array-slice': 114,
+            '../internals/fails': 147,
+            '../internals/function-apply': 149,
+            '../internals/global': 160
+          }
+        ],
+        336: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('../internals/array-buffer-view-core').exportTypedArrayMethod,
+              s = e('../internals/fails'),
+              i = e('../internals/global'),
+              e = e('../internals/function-uncurry-this'),
+              i = i.Uint8Array,
+              i = (i && i.prototype) || {},
+              o = [].toString,
+              a = e([].join),
+              e =
+                (s(function () {
+                  o.call({});
+                }) &&
+                  (o = function () {
+                    return a(this);
+                  }),
+                i.toString != o);
+            n('toString', o, e);
+          },
+          {
+            '../internals/array-buffer-view-core': 100,
+            '../internals/fails': 147,
+            '../internals/function-uncurry-this': 154,
+            '../internals/global': 160
+          }
+        ],
+        337: [
+          function (e, t, r) {
+            e('../internals/typed-array-constructor')('Uint8', function (n) {
+              return function (e, t, r) {
+                return n(this, e, t, r);
+              };
+            });
+          },
+          { '../internals/typed-array-constructor': 255 }
+        ],
+        338: [
+          function (e, t, r) {
+            function n(t) {
+              if (t && t.forEach !== c)
+                try {
+                  l(t, 'forEach', c);
+                } catch (e) {
+                  t.forEach = c;
+                }
+            }
+            var s,
+              i = e('../internals/global'),
+              o = e('../internals/dom-iterables'),
+              a = e('../internals/dom-token-list-prototype'),
+              c = e('../internals/array-for-each'),
+              l = e('../internals/create-non-enumerable-property');
+            for (s in o) o[s] && n(i[s] && i[s].prototype);
+            n(a);
+          },
+          {
+            '../internals/array-for-each': 104,
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/dom-iterables': 133,
+            '../internals/dom-token-list-prototype': 134,
+            '../internals/global': 160
+          }
+        ],
+        339: [
+          function (e, t, r) {
+            function n(t, e) {
+              if (t) {
+                if (t[u] !== f)
+                  try {
+                    l(t, u, f);
+                  } catch (e) {
+                    t[u] = f;
+                  }
+                if ((t[p] || l(t, p, e), o[e]))
+                  for (var r in c)
+                    if (t[r] !== c[r])
+                      try {
+                        l(t, r, c[r]);
+                      } catch (e) {
+                        t[r] = c[r];
+                      }
+              }
+            }
+            var s,
+              i = e('../internals/global'),
+              o = e('../internals/dom-iterables'),
+              a = e('../internals/dom-token-list-prototype'),
+              c = e('../modules/es.array.iterator'),
+              l = e('../internals/create-non-enumerable-property'),
+              e = e('../internals/well-known-symbol'),
+              u = e('iterator'),
+              p = e('toStringTag'),
+              f = c.values;
+            for (s in o) n(i[s] && i[s].prototype, s);
+            n(a, 'DOMTokenList');
+          },
+          {
+            '../internals/create-non-enumerable-property': 126,
+            '../internals/dom-iterables': 133,
+            '../internals/dom-token-list-prototype': 134,
+            '../internals/global': 160,
+            '../internals/well-known-symbol': 265,
+            '../modules/es.array.iterator': 275
+          }
+        ],
+        340: [
+          function (e, t, r) {
+            function n(e) {
+              return Object.prototype.toString.call(e);
+            }
+            (r.isArray = function (e) {
+              return Array.isArray ? Array.isArray(e) : '[object Array]' === n(e);
+            }),
+              (r.isBoolean = function (e) {
+                return 'boolean' == typeof e;
+              }),
+              (r.isNull = function (e) {
+                return null === e;
+              }),
+              (r.isNullOrUndefined = function (e) {
+                return null == e;
+              }),
+              (r.isNumber = function (e) {
+                return 'number' == typeof e;
+              }),
+              (r.isString = function (e) {
+                return 'string' == typeof e;
+              }),
+              (r.isSymbol = function (e) {
+                return 'symbol' == typeof e;
+              }),
+              (r.isUndefined = function (e) {
+                return void 0 === e;
+              }),
+              (r.isRegExp = function (e) {
+                return '[object RegExp]' === n(e);
+              }),
+              (r.isObject = function (e) {
+                return 'object' == typeof e && null !== e;
+              }),
+              (r.isDate = function (e) {
+                return '[object Date]' === n(e);
+              }),
+              (r.isError = function (e) {
+                return '[object Error]' === n(e) || e instanceof Error;
+              }),
+              (r.isFunction = function (e) {
+                return 'function' == typeof e;
+              }),
+              (r.isPrimitive = function (e) {
+                return (
+                  null === e ||
+                  'boolean' == typeof e ||
+                  'number' == typeof e ||
+                  'string' == typeof e ||
+                  'symbol' == typeof e ||
+                  void 0 === e
+                );
+              }),
+              (r.isBuffer = e('buffer').Buffer.isBuffer);
+          },
+          { buffer: 89 }
+        ],
+        341: [
+          function (e, t, r) {
+            !(function (e) {
+              'use strict';
+              (b = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZWN]|'[^']*'|'[^']*'/g),
+                (g =
+                  /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g),
+                (v = /[^-+\dA-Z]/g);
+              var b,
+                g,
+                v,
+                j = function (e, t, r, n) {
+                  if (
+                    (1 !== arguments.length ||
+                      'string' !==
+                        (function (e) {
+                          if (null === e) return 'null';
+                          if (void 0 === e) return 'undefined';
+                          if ('object' != typeof e) return typeof e;
+                          if (Array.isArray(e)) return 'array';
+                          return {}.toString.call(e).slice(8, -1).toLowerCase();
+                        })(e) ||
+                      /\d/.test(e) ||
+                      ((t = e), (e = void 0)),
+                    (e = e || new Date()) instanceof Date || (e = new Date(e)),
+                    isNaN(e))
+                  )
+                    throw TypeError('Invalid date');
+                  var s,
+                    i = (t = String(j.masks[t] || t || j.masks.default)).slice(0, 4),
+                    i =
+                      (('UTC:' !== i && 'GMT:' !== i) || ((t = t.slice(4)), (r = !0), 'GMT:' === i && (n = !0)),
+                      r ? 'getUTC' : 'get'),
+                    o = e[i + 'Date'](),
+                    a = e[i + 'Day'](),
+                    c = e[i + 'Month'](),
+                    l = e[i + 'FullYear'](),
+                    u = e[i + 'Hours'](),
+                    p = e[i + 'Minutes'](),
+                    f = e[i + 'Seconds'](),
+                    i = e[i + 'Milliseconds'](),
+                    d = r ? 0 : e.getTimezoneOffset(),
+                    h =
+                      ((h = e),
+                      (h = new Date(h.getFullYear(), h.getMonth(), h.getDate())).setDate(
+                        h.getDate() - ((h.getDay() + 6) % 7) + 3
+                      ),
+                      (m = new Date(h.getFullYear(), 0, 4)).setDate(m.getDate() - ((m.getDay() + 6) % 7) + 3),
+                      (s = h.getTimezoneOffset() - m.getTimezoneOffset()),
+                      h.setHours(h.getHours() - s),
+                      (s = (h - m) / 6048e5),
+                      1 + Math.floor(s)),
+                    m = (function (e) {
+                      e = e.getDay();
+                      0 === e && (e = 7);
+                      return e;
+                    })(e),
+                    y = {
+                      d: o,
+                      dd: w(o),
+                      ddd: j.i18n.dayNames[a],
+                      dddd: j.i18n.dayNames[a + 7],
+                      m: c + 1,
+                      mm: w(c + 1),
+                      mmm: j.i18n.monthNames[c],
+                      mmmm: j.i18n.monthNames[c + 12],
+                      yy: String(l).slice(2),
+                      yyyy: l,
+                      h: u % 12 || 12,
+                      hh: w(u % 12 || 12),
+                      H: u,
+                      HH: w(u),
+                      M: p,
+                      MM: w(p),
+                      s: f,
+                      ss: w(f),
+                      l: w(i, 3),
+                      L: w(Math.round(i / 10)),
+                      t: u < 12 ? 'a' : 'p',
+                      tt: u < 12 ? 'am' : 'pm',
+                      T: u < 12 ? 'A' : 'P',
+                      TT: u < 12 ? 'AM' : 'PM',
+                      Z: n ? 'GMT' : r ? 'UTC' : (String(e).match(g) || ['']).pop().replace(v, ''),
+                      o: (0 < d ? '-' : '+') + w(100 * Math.floor(Math.abs(d) / 60) + (Math.abs(d) % 60), 4),
+                      S: ['th', 'st', 'nd', 'rd'][3 < o % 10 ? 0 : (((o % 100) - (o % 10) != 10) * o) % 10],
+                      W: h,
+                      N: m
+                    };
+                  return t.replace(b, function (e) {
+                    return e in y ? y[e] : e.slice(1, e.length - 1);
+                  });
+                };
+              function w(e, t) {
+                for (e = String(e), t = t || 2; e.length < t; ) e = '0' + e;
+                return e;
+              }
+              (j.masks = {
+                default: 'ddd mmm dd yyyy HH:MM:ss',
+                shortDate: 'm/d/yy',
+                mediumDate: 'mmm d, yyyy',
+                longDate: 'mmmm d, yyyy',
+                fullDate: 'dddd, mmmm d, yyyy',
+                shortTime: 'h:MM TT',
+                mediumTime: 'h:MM:ss TT',
+                longTime: 'h:MM:ss TT Z',
+                isoDate: 'yyyy-mm-dd',
+                isoTime: 'HH:MM:ss',
+                isoDateTime: "yyyy-mm-dd'T'HH:MM:sso",
+                isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'",
+                expiresHeaderFormat: 'ddd, dd mmm yyyy HH:MM:ss Z'
+              }),
+                (j.i18n = {
+                  dayNames: [
+                    'Sun',
+                    'Mon',
+                    'Tue',
+                    'Wed',
+                    'Thu',
+                    'Fri',
+                    'Sat',
+                    'Sunday',
+                    'Monday',
+                    'Tuesday',
+                    'Wednesday',
+                    'Thursday',
+                    'Friday',
+                    'Saturday'
+                  ],
+                  monthNames: [
+                    'Jan',
+                    'Feb',
+                    'Mar',
+                    'Apr',
+                    'May',
+                    'Jun',
+                    'Jul',
+                    'Aug',
+                    'Sep',
+                    'Oct',
+                    'Nov',
+                    'Dec',
+                    'January',
+                    'February',
+                    'March',
+                    'April',
+                    'May',
+                    'June',
+                    'July',
+                    'August',
+                    'September',
+                    'October',
+                    'November',
+                    'December'
+                  ]
+                }),
+                'object' == typeof r ? (t.exports = j) : (e.dateFormat = j);
+            })(this);
+          },
+          {}
+        ],
+        342: [
+          function (e, t, r) {
+            'use strict';
+            var o = /["'&<>]/;
+            t.exports = function (e) {
+              var t,
+                r = '' + e,
+                e = o.exec(r);
+              if (!e) return r;
+              var n = '',
+                s = 0,
+                i = 0;
+              for (s = e.index; s < r.length; s++) {
+                switch (r.charCodeAt(s)) {
+                  case 34:
+                    t = '&quot;';
+                    break;
+                  case 38:
+                    t = '&amp;';
+                    break;
+                  case 39:
+                    t = '&#39;';
+                    break;
+                  case 60:
+                    t = '&lt;';
+                    break;
+                  case 62:
+                    t = '&gt;';
+                    break;
+                  default:
+                    continue;
+                }
+                i !== s && (n += r.substring(i, s)), (i = s + 1), (n += t);
+              }
+              return i !== s ? n + r.substring(i, s) : n;
+            };
+          },
+          {}
+        ],
+        343: [
+          function (e, t, r) {
+            function n() {
+              (this._events = this._events || {}), (this._maxListeners = this._maxListeners || void 0);
+            }
+            function c(e) {
+              return 'function' == typeof e;
+            }
+            function l(e) {
+              return 'object' == typeof e && null !== e;
+            }
+            function u(e) {
+              return void 0 === e;
+            }
+            (((t.exports = n).EventEmitter = n).prototype._events = void 0),
+              (n.prototype._maxListeners = void 0),
+              (n.defaultMaxListeners = 10),
+              (n.prototype.setMaxListeners = function (e) {
+                if ('number' != typeof e || e < 0 || isNaN(e)) throw TypeError('n must be a positive number');
+                return (this._maxListeners = e), this;
+              }),
+              (n.prototype.emit = function (e) {
+                var t, r, n, s, i, o, a;
+                if (
+                  (this._events || (this._events = {}), 'error' === e) &&
+                  (!this._events.error || (l(this._events.error) && !this._events.error.length))
+                )
+                  throw (a = arguments[1]) instanceof Error
+                    ? a
+                    : (((o = new Error('Uncaught, unspecified "error" event. (' + a + ')')).context = a), o);
+                if (u((t = this._events[e]))) return !1;
+                if (c(t))
+                  switch (arguments.length) {
+                    case 1:
+                      t.call(this);
+                      break;
+                    case 2:
+                      t.call(this, arguments[1]);
+                      break;
+                    case 3:
+                      t.call(this, arguments[1], arguments[2]);
+                      break;
+                    default:
+                      (n = Array.prototype.slice.call(arguments, 1)), t.apply(this, n);
+                  }
+                else if (l(t))
+                  for (n = Array.prototype.slice.call(arguments, 1), r = (i = t.slice()).length, s = 0; s < r; s++)
+                    i[s].apply(this, n);
+                return !0;
+              }),
+              (n.prototype.on = n.prototype.addListener =
+                function (e, t) {
+                  if (c(t))
+                    return (
+                      this._events || (this._events = {}),
+                      this._events.newListener && this.emit('newListener', e, c(t.listener) ? t.listener : t),
+                      this._events[e]
+                        ? l(this._events[e])
+                          ? this._events[e].push(t)
+                          : (this._events[e] = [this._events[e], t])
+                        : (this._events[e] = t),
+                      l(this._events[e]) &&
+                        !this._events[e].warned &&
+                        (t = u(this._maxListeners) ? n.defaultMaxListeners : this._maxListeners) &&
+                        0 < t &&
+                        this._events[e].length > t &&
+                        ((this._events[e].warned = !0),
+                        console.error(
+                          '(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',
+                          this._events[e].length
+                        ),
+                        'function' == typeof console.trace && console.trace()),
+                      this
+                    );
+                  throw TypeError('listener must be a function');
+                }),
+              (n.prototype.once = function (e, t) {
+                if (!c(t)) throw TypeError('listener must be a function');
+                var r = !1;
+                function n() {
+                  this.removeListener(e, n), r || ((r = !0), t.apply(this, arguments));
+                }
+                return (n.listener = t), this.on(e, n), this;
+              }),
+              (n.prototype.removeListener = function (e, t) {
+                var r, n, s, i;
+                if (!c(t)) throw TypeError('listener must be a function');
+                if (!this._events || !this._events[e]) return this;
+                if (((s = (r = this._events[e]).length), (n = -1), r === t || (c(r.listener) && r.listener === t)))
+                  delete this._events[e], this._events.removeListener && this.emit('removeListener', e, t);
+                else if (l(r)) {
+                  for (i = s; 0 < i--; )
+                    if (r[i] === t || (r[i].listener && r[i].listener === t)) {
+                      n = i;
+                      break;
+                    }
+                  if (n < 0) return this;
+                  1 === r.length ? ((r.length = 0), delete this._events[e]) : r.splice(n, 1),
+                    this._events.removeListener && this.emit('removeListener', e, t);
+                }
+                return this;
+              }),
+              (n.prototype.removeAllListeners = function (e) {
+                var t, r;
+                if (!this._events) return this;
+                if (!this._events.removeListener)
+                  return 0 === arguments.length ? (this._events = {}) : this._events[e] && delete this._events[e], this;
+                if (0 === arguments.length) {
+                  for (t in this._events) 'removeListener' !== t && this.removeAllListeners(t);
+                  return this.removeAllListeners('removeListener'), (this._events = {}), this;
+                }
+                if (c((r = this._events[e]))) this.removeListener(e, r);
+                else if (r) for (; r.length; ) this.removeListener(e, r[r.length - 1]);
+                return delete this._events[e], this;
+              }),
+              (n.prototype.listeners = function (e) {
+                e =
+                  this._events && this._events[e]
+                    ? c(this._events[e])
+                      ? [this._events[e]]
+                      : this._events[e].slice()
+                    : [];
+                return e;
+              }),
+              (n.prototype.listenerCount = function (e) {
+                if (this._events) {
+                  e = this._events[e];
+                  if (c(e)) return 1;
+                  if (e) return e.length;
+                }
+                return 0;
+              }),
+              (n.listenerCount = function (e, t) {
+                return e.listenerCount(t);
+              });
+          },
+          {}
+        ],
+        344: [
+          function (e, t, r) {
+            var n,
+              s = e('http'),
+              i = t.exports;
+            for (n in s) s.hasOwnProperty(n) && (i[n] = s[n]);
+            i.request = function (e, t) {
+              return ((e = e || {}).scheme = 'https'), (e.protocol = 'https:'), s.request.call(this, e, t);
+            };
+          },
+          { http: 442 }
+        ],
+        345: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('util'),
+              s = e('ms');
+            t.exports = function (e) {
+              if ('number' == typeof e) return e;
+              var t = s(e);
+              return (
+                void 0 === t &&
+                  ((e = new Error(n.format('humanize-ms(%j) result undefined', e))), console.warn(e.stack)),
+                t
+              );
+            };
+          },
+          { ms: 361, util: 394 }
+        ],
+        346: [
+          function (e, t, r) {
+            (r.read = function (e, t, r, n, s) {
+              var i,
+                o,
+                a = 8 * s - n - 1,
+                c = (1 << a) - 1,
+                l = c >> 1,
+                u = -7,
+                p = r ? s - 1 : 0,
+                f = r ? -1 : 1,
+                s = e[t + p];
+              for (p += f, i = s & ((1 << -u) - 1), s >>= -u, u += a; 0 < u; i = 256 * i + e[t + p], p += f, u -= 8);
+              for (o = i & ((1 << -u) - 1), i >>= -u, u += n; 0 < u; o = 256 * o + e[t + p], p += f, u -= 8);
+              if (0 === i) i = 1 - l;
+              else {
+                if (i === c) return o ? NaN : (1 / 0) * (s ? -1 : 1);
+                (o += Math.pow(2, n)), (i -= l);
+              }
+              return (s ? -1 : 1) * o * Math.pow(2, i - n);
+            }),
+              (r.write = function (e, t, r, n, s, i) {
+                var o,
+                  a,
+                  c = 8 * i - s - 1,
+                  l = (1 << c) - 1,
+                  u = l >> 1,
+                  p = 23 === s ? Math.pow(2, -24) - Math.pow(2, -77) : 0,
+                  f = n ? 0 : i - 1,
+                  d = n ? 1 : -1,
+                  i = t < 0 || (0 === t && 1 / t < 0) ? 1 : 0;
+                for (
+                  t = Math.abs(t),
+                    isNaN(t) || t === 1 / 0
+                      ? ((a = isNaN(t) ? 1 : 0), (o = l))
+                      : ((o = Math.floor(Math.log(t) / Math.LN2)),
+                        t * (n = Math.pow(2, -o)) < 1 && (o--, (n *= 2)),
+                        2 <= (t += 1 <= o + u ? p / n : p * Math.pow(2, 1 - u)) * n && (o++, (n /= 2)),
+                        l <= o + u
+                          ? ((a = 0), (o = l))
+                          : 1 <= o + u
+                          ? ((a = (t * n - 1) * Math.pow(2, s)), (o += u))
+                          : ((a = t * Math.pow(2, u - 1) * Math.pow(2, s)), (o = 0)));
+                  8 <= s;
+                  e[r + f] = 255 & a, f += d, a /= 256, s -= 8
+                );
+                for (o = (o << s) | a, c += s; 0 < c; e[r + f] = 255 & o, f += d, o /= 256, c -= 8);
+                e[r + f - d] |= 128 * i;
+              });
+          },
+          {}
+        ],
+        347: [
+          function (e, t, r) {
+            'use strict';
+            var n,
+              s,
+              i,
+              o = [
+                e('./nextTick'),
+                e('./queueMicrotask'),
+                e('./mutation.js'),
+                e('./messageChannel'),
+                e('./stateChange'),
+                e('./timeout')
+              ],
+              a = -1,
+              c = [],
+              l = !1;
+            function u() {
+              n && s && ((n = !1), s.length ? (c = s.concat(c)) : (a = -1), c.length && p());
+            }
+            function p() {
+              if (!n) {
+                n = !(l = !1);
+                for (var e = c.length, t = setTimeout(u); e; ) {
+                  for (s = c, c = []; s && ++a < e; ) s[a].run();
+                  (a = -1), (e = c.length);
+                }
+                (s = null), (n = !(a = -1)), clearTimeout(t);
+              }
+            }
+            for (var f = -1, d = o.length; ++f < d; )
+              if (o[f] && o[f].test && o[f].test()) {
+                i = o[f].install(p);
+                break;
+              }
+            function h(e, t) {
+              (this.fun = e), (this.array = t);
+            }
+            (h.prototype.run = function () {
+              var e = this.fun,
+                t = this.array;
+              switch (t.length) {
+                case 0:
+                  return e();
+                case 1:
+                  return e(t[0]);
+                case 2:
+                  return e(t[0], t[1]);
+                case 3:
+                  return e(t[0], t[1], t[2]);
+                default:
+                  return e.apply(null, t);
+              }
+            }),
+              (t.exports = function (e) {
+                var t = new Array(arguments.length - 1);
+                if (1 < arguments.length) for (var r = 1; r < arguments.length; r++) t[r - 1] = arguments[r];
+                c.push(new h(e, t)), l || n || ((l = !0), i());
+              });
+          },
+          {
+            './messageChannel': 348,
+            './mutation.js': 349,
+            './nextTick': 87,
+            './queueMicrotask': 350,
+            './stateChange': 351,
+            './timeout': 352
+          }
+        ],
+        348: [
+          function (e, t, n) {
+            !function (r) {
+              !function () {
+                'use strict';
+                (n.test = function () {
+                  return !r.setImmediate && void 0 !== r.MessageChannel;
+                }),
+                  (n.install = function (e) {
+                    var t = new r.MessageChannel();
+                    return (
+                      (t.port1.onmessage = e),
+                      function () {
+                        t.port2.postMessage(0);
+                      }
+                    );
+                  });
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        349: [
+          function (e, t, r) {
+            !function (s) {
+              !function () {
+                'use strict';
+                var n = s.MutationObserver || s.WebKitMutationObserver;
+                (r.test = function () {
+                  return n;
+                }),
+                  (r.install = function (e) {
+                    var t = 0,
+                      e = new n(e),
+                      r = s.document.createTextNode('');
+                    return (
+                      e.observe(r, { characterData: !0 }),
+                      function () {
+                        r.data = t = ++t % 2;
+                      }
+                    );
+                  });
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        350: [
+          function (e, t, r) {
+            !function (t) {
+              !function () {
+                'use strict';
+                (r.test = function () {
+                  return 'function' == typeof t.queueMicrotask;
+                }),
+                  (r.install = function (e) {
+                    return function () {
+                      t.queueMicrotask(e);
+                    };
+                  });
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        351: [
+          function (e, t, n) {
+            !function (r) {
+              !function () {
+                'use strict';
+                (n.test = function () {
+                  return 'document' in r && 'onreadystatechange' in r.document.createElement('script');
+                }),
+                  (n.install = function (t) {
+                    return function () {
+                      var e = r.document.createElement('script');
+                      return (
+                        (e.onreadystatechange = function () {
+                          t(), (e.onreadystatechange = null), e.parentNode.removeChild(e), (e = null);
+                        }),
+                        r.document.documentElement.appendChild(e),
+                        t
+                      );
+                    };
+                  });
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        352: [
+          function (e, t, r) {
+            'use strict';
+            (r.test = function () {
+              return !0;
+            }),
+              (r.install = function (e) {
+                return function () {
+                  setTimeout(e, 0);
+                };
+              });
+          },
+          {}
+        ],
+        353: [
+          function (e, t, r) {
+            'function' == typeof Object.create
+              ? (t.exports = function (e, t) {
+                  t &&
+                    ((e.super_ = t),
+                    (e.prototype = Object.create(t.prototype, {
+                      constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 }
+                    })));
+                })
+              : (t.exports = function (e, t) {
+                  var r;
+                  t &&
+                    ((e.super_ = t),
+                    ((r = function () {}).prototype = t.prototype),
+                    (e.prototype = new r()),
+                    (e.prototype.constructor = e));
+                });
+          },
+          {}
+        ],
+        354: [
+          function (e, t, r) {
+            function n(e) {
+              return !!e.constructor && 'function' == typeof e.constructor.isBuffer && e.constructor.isBuffer(e);
+            }
+            t.exports = function (e) {
+              return (
+                null != e &&
+                (n(e) ||
+                  ('function' == typeof (t = e).readFloatLE && 'function' == typeof t.slice && n(t.slice(0, 0))) ||
+                  !!e._isBuffer)
+              );
+              var t;
+            };
+          },
+          {}
+        ],
+        355: [
+          function (e, t, r) {
+            var n = {}.toString;
+            t.exports =
+              Array.isArray ||
+              function (e) {
+                return '[object Array]' == n.call(e);
+              };
+          },
+          {}
+        ],
+        356: [
+          function (e, k, n) {
+            !function (r) {
+              !function () {
+                var e, t;
+                (e =
+                  'undefined' != typeof self ? self : 'undefined' != typeof window ? window : void 0 !== r ? r : this),
+                  (t = function (t) {
+                    'use strict';
+                    function r(e) {
+                      var t;
+                      return e.length < 2
+                        ? (t = e.charCodeAt(0)) < 128
+                          ? e
+                          : t < 2048
+                          ? b(192 | (t >>> 6)) + b(128 | (63 & t))
+                          : b(224 | ((t >>> 12) & 15)) + b(128 | ((t >>> 6) & 63)) + b(128 | (63 & t))
+                        : ((t = 65536 + 1024 * (e.charCodeAt(0) - 55296) + (e.charCodeAt(1) - 56320)),
+                          b(240 | ((t >>> 18) & 7)) +
+                            b(128 | ((t >>> 12) & 63)) +
+                            b(128 | ((t >>> 6) & 63)) +
+                            b(128 | (63 & t)));
+                    }
+                    function n(e) {
+                      var t = [0, 2, 1][e.length % 3],
+                        e =
+                          (e.charCodeAt(0) << 16) |
+                          ((1 < e.length ? e.charCodeAt(1) : 0) << 8) |
+                          (2 < e.length ? e.charCodeAt(2) : 0);
+                      return [
+                        m.charAt(e >>> 18),
+                        m.charAt((e >>> 12) & 63),
+                        2 <= t ? '=' : m.charAt((e >>> 6) & 63),
+                        1 <= t ? '=' : m.charAt(63 & e)
+                      ].join('');
+                    }
+                    function s(e) {
+                      return j(v(String(e)));
+                    }
+                    function c(e) {
+                      return e
+                        .replace(/[+\/]/g, function (e) {
+                          return '+' == e ? '-' : '_';
+                        })
+                        .replace(/=/g, '');
+                    }
+                    function i(e, t) {
+                      return t ? c(s(e)) : s(e);
+                    }
+                    function o(e) {
+                      switch (e.length) {
+                        case 4:
+                          var t =
+                            (((7 & e.charCodeAt(0)) << 18) |
+                              ((63 & e.charCodeAt(1)) << 12) |
+                              ((63 & e.charCodeAt(2)) << 6) |
+                              (63 & e.charCodeAt(3))) -
+                            65536;
+                          return b(55296 + (t >>> 10)) + b(56320 + (1023 & t));
+                        case 3:
+                          return b(
+                            ((15 & e.charCodeAt(0)) << 12) | ((63 & e.charCodeAt(1)) << 6) | (63 & e.charCodeAt(2))
+                          );
+                        default:
+                          return b(((31 & e.charCodeAt(0)) << 6) | (63 & e.charCodeAt(1)));
+                      }
+                    }
+                    function a(e) {
+                      var t = (r = e.length) % 4,
+                        r =
+                          (0 < r ? y[e.charAt(0)] << 18 : 0) |
+                          (1 < r ? y[e.charAt(1)] << 12 : 0) |
+                          (2 < r ? y[e.charAt(2)] << 6 : 0) |
+                          (3 < r ? y[e.charAt(3)] : 0);
+                      return (
+                        ((e = [b(r >>> 16), b((r >>> 8) & 255), b(255 & r)]).length -= [0, 0, 2, 1][t]), e.join('')
+                      );
+                    }
+                    function l(e) {
+                      return T(String(e).replace(/[^A-Za-z0-9\+\/]/g, ''));
+                    }
+                    function u(e) {
+                      return String(e)
+                        .replace(/[-_]/g, function (e) {
+                          return '-' == e ? '+' : '/';
+                        })
+                        .replace(/[^A-Za-z0-9\+\/]/g, '');
+                    }
+                    function e(e) {
+                      return (e = u(e)), x(T(e));
+                    }
+                    var p,
+                      f,
+                      d,
+                      h = (t = t || {}).Base64,
+                      m = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
+                      y = (function (e) {
+                        for (var t = {}, r = 0, n = e.length; r < n; r++) t[e.charAt(r)] = r;
+                        return t;
+                      })(m),
+                      b = String.fromCharCode,
+                      g = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,
+                      v = function (e) {
+                        return e.replace(g, r);
+                      },
+                      j =
+                        t.btoa && 'function' == typeof t.btoa
+                          ? function (e) {
+                              return t.btoa(e);
+                            }
+                          : function (e) {
+                              if (e.match(/[^\x00-\xFF]/))
+                                throw new RangeError('The string contains invalid characters.');
+                              return e.replace(/[\s\S]{1,3}/g, n);
+                            },
+                      w =
+                        (t.Uint8Array &&
+                          (p = function (e, t) {
+                            for (var r = '', n = 0, s = e.length; n < s; n += 3) {
+                              var i = e[n],
+                                o = e[n + 1],
+                                a = e[n + 2],
+                                i = (i << 16) | (o << 8) | a;
+                              r +=
+                                m.charAt(i >>> 18) +
+                                m.charAt((i >>> 12) & 63) +
+                                (void 0 !== o ? m.charAt((i >>> 6) & 63) : '=') +
+                                (void 0 !== a ? m.charAt(63 & i) : '=');
+                            }
+                            return t ? c(r) : r;
+                          }),
+                        /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g),
+                      x = function (e) {
+                        return e.replace(w, o);
+                      },
+                      T =
+                        t.atob && 'function' == typeof t.atob
+                          ? function (e) {
+                              return t.atob(e);
+                            }
+                          : function (e) {
+                              return e.replace(/\S{1,4}/g, a);
+                            };
+                    t.Uint8Array &&
+                      (f = function (e) {
+                        return Uint8Array.from(l(u(e)), function (e) {
+                          return e.charCodeAt(0);
+                        });
+                      });
+                    return (
+                      (t.Base64 = {
+                        VERSION: '2.6.4',
+                        atob: l,
+                        btoa: j,
+                        fromBase64: e,
+                        toBase64: i,
+                        utob: v,
+                        encode: i,
+                        encodeURI: function (e) {
+                          return i(e, !0);
+                        },
+                        btou: x,
+                        decode: e,
+                        noConflict: function () {
+                          var e = t.Base64;
+                          return (t.Base64 = h), e;
+                        },
+                        fromUint8Array: p,
+                        toUint8Array: f
+                      }),
+                      'function' == typeof Object.defineProperty &&
+                        ((d = function (e) {
+                          return { value: e, enumerable: !1, writable: !0, configurable: !0 };
+                        }),
+                        (t.Base64.extendString = function () {
+                          Object.defineProperty(
+                            String.prototype,
+                            'fromBase64',
+                            d(function () {
+                              return e(this);
+                            })
+                          ),
+                            Object.defineProperty(
+                              String.prototype,
+                              'toBase64',
+                              d(function (e) {
+                                return i(this, e);
+                              })
+                            ),
+                            Object.defineProperty(
+                              String.prototype,
+                              'toBase64URI',
+                              d(function () {
+                                return i(this, !0);
+                              })
+                            );
+                        })),
+                      t.Meteor && (Base64 = t.Base64),
+                      void 0 !== k && k.exports && (k.exports.Base64 = t.Base64),
+                      { Base64: t.Base64 }
+                    );
+                  }),
+                  'object' == typeof n && void 0 !== k ? (k.exports = t(e)) : t(e);
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        357: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = function (r, n, s) {
+              if (!r) throw new TypeError('argument dest is required');
+              if (!n) throw new TypeError('argument src is required');
+              void 0 === s && (s = !0);
+              return (
+                Object.getOwnPropertyNames(n).forEach(function (e) {
+                  var t;
+                  (!s && i.call(r, e)) || ((t = Object.getOwnPropertyDescriptor(n, e)), Object.defineProperty(r, e, t));
+                }),
+                r
+              );
+            };
+            var i = Object.prototype.hasOwnProperty;
+          },
+          {}
+        ],
+        358: [
+          function (e, t, r) {
+            'use strict';
+            function n() {
+              (this._types = Object.create(null)), (this._extensions = Object.create(null));
+              for (var e = 0; e < arguments.length; e++) this.define(arguments[e]);
+              (this.define = this.define.bind(this)),
+                (this.getType = this.getType.bind(this)),
+                (this.getExtension = this.getExtension.bind(this));
+            }
+            e('core-js/modules/es.array.map.js'),
+              e('core-js/modules/es.regexp.exec.js'),
+              e('core-js/modules/es.string.replace.js'),
+              e('core-js/modules/es.regexp.constructor.js'),
+              e('core-js/modules/es.regexp.to-string.js'),
+              (n.prototype.define = function (e, t) {
+                for (var r in e) {
+                  for (
+                    var n,
+                      s = e[r].map(function (e) {
+                        return e.toLowerCase();
+                      }),
+                      r = r.toLowerCase(),
+                      i = 0;
+                    i < s.length;
+                    i++
+                  ) {
+                    var o = s[i];
+                    if ('*' !== o[0]) {
+                      if (!t && o in this._types)
+                        throw new Error(
+                          'Attempt to change mapping for "' +
+                            o +
+                            '" extension from "' +
+                            this._types[o] +
+                            '" to "' +
+                            r +
+                            '". Pass `force=true` to allow this, otherwise remove "' +
+                            o +
+                            '" from the list of extensions for "' +
+                            r +
+                            '".'
+                        );
+                      this._types[o] = r;
+                    }
+                  }
+                  (!t && this._extensions[r]) || ((n = s[0]), (this._extensions[r] = '*' !== n[0] ? n : n.substr(1)));
+                }
+              }),
+              (n.prototype.getType = function (e) {
+                var t = (e = String(e)).replace(/^.*[/\\]/, '').toLowerCase(),
+                  r = t.replace(/^.*\./, '').toLowerCase(),
+                  e = t.length < e.length;
+                return ((r.length < t.length - 1 || !e) && this._types[r]) || null;
+              }),
+              (n.prototype.getExtension = function (e) {
+                return ((e = /^\s*([^;\s]*)/.test(e) && RegExp.$1) && this._extensions[e.toLowerCase()]) || null;
+              }),
+              (t.exports = n);
+          },
+          {
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.regexp.constructor.js': 298,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.replace.js': 304
+          }
+        ],
+        359: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('./Mime');
+            t.exports = new n(e('./types/standard'));
+          },
+          { './Mime': 358, './types/standard': 360 }
+        ],
+        360: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = {
+              'application/andrew-inset': ['ez'],
+              'application/applixware': ['aw'],
+              'application/atom+xml': ['atom'],
+              'application/atomcat+xml': ['atomcat'],
+              'application/atomdeleted+xml': ['atomdeleted'],
+              'application/atomsvc+xml': ['atomsvc'],
+              'application/atsc-dwd+xml': ['dwd'],
+              'application/atsc-held+xml': ['held'],
+              'application/atsc-rsat+xml': ['rsat'],
+              'application/bdoc': ['bdoc'],
+              'application/calendar+xml': ['xcs'],
+              'application/ccxml+xml': ['ccxml'],
+              'application/cdfx+xml': ['cdfx'],
+              'application/cdmi-capability': ['cdmia'],
+              'application/cdmi-container': ['cdmic'],
+              'application/cdmi-domain': ['cdmid'],
+              'application/cdmi-object': ['cdmio'],
+              'application/cdmi-queue': ['cdmiq'],
+              'application/cu-seeme': ['cu'],
+              'application/dash+xml': ['mpd'],
+              'application/davmount+xml': ['davmount'],
+              'application/docbook+xml': ['dbk'],
+              'application/dssc+der': ['dssc'],
+              'application/dssc+xml': ['xdssc'],
+              'application/ecmascript': ['es', 'ecma'],
+              'application/emma+xml': ['emma'],
+              'application/emotionml+xml': ['emotionml'],
+              'application/epub+zip': ['epub'],
+              'application/exi': ['exi'],
+              'application/express': ['exp'],
+              'application/fdt+xml': ['fdt'],
+              'application/font-tdpfr': ['pfr'],
+              'application/geo+json': ['geojson'],
+              'application/gml+xml': ['gml'],
+              'application/gpx+xml': ['gpx'],
+              'application/gxf': ['gxf'],
+              'application/gzip': ['gz'],
+              'application/hjson': ['hjson'],
+              'application/hyperstudio': ['stk'],
+              'application/inkml+xml': ['ink', 'inkml'],
+              'application/ipfix': ['ipfix'],
+              'application/its+xml': ['its'],
+              'application/java-archive': ['jar', 'war', 'ear'],
+              'application/java-serialized-object': ['ser'],
+              'application/java-vm': ['class'],
+              'application/javascript': ['js', 'mjs'],
+              'application/json': ['json', 'map'],
+              'application/json5': ['json5'],
+              'application/jsonml+json': ['jsonml'],
+              'application/ld+json': ['jsonld'],
+              'application/lgr+xml': ['lgr'],
+              'application/lost+xml': ['lostxml'],
+              'application/mac-binhex40': ['hqx'],
+              'application/mac-compactpro': ['cpt'],
+              'application/mads+xml': ['mads'],
+              'application/manifest+json': ['webmanifest'],
+              'application/marc': ['mrc'],
+              'application/marcxml+xml': ['mrcx'],
+              'application/mathematica': ['ma', 'nb', 'mb'],
+              'application/mathml+xml': ['mathml'],
+              'application/mbox': ['mbox'],
+              'application/mediaservercontrol+xml': ['mscml'],
+              'application/metalink+xml': ['metalink'],
+              'application/metalink4+xml': ['meta4'],
+              'application/mets+xml': ['mets'],
+              'application/mmt-aei+xml': ['maei'],
+              'application/mmt-usd+xml': ['musd'],
+              'application/mods+xml': ['mods'],
+              'application/mp21': ['m21', 'mp21'],
+              'application/mp4': ['mp4s', 'm4p'],
+              'application/msword': ['doc', 'dot'],
+              'application/mxf': ['mxf'],
+              'application/n-quads': ['nq'],
+              'application/n-triples': ['nt'],
+              'application/node': ['cjs'],
+              'application/octet-stream': [
+                'bin',
+                'dms',
+                'lrf',
+                'mar',
+                'so',
+                'dist',
+                'distz',
+                'pkg',
+                'bpk',
+                'dump',
+                'elc',
+                'deploy',
+                'exe',
+                'dll',
+                'deb',
+                'dmg',
+                'iso',
+                'img',
+                'msi',
+                'msp',
+                'msm',
+                'buffer'
+              ],
+              'application/oda': ['oda'],
+              'application/oebps-package+xml': ['opf'],
+              'application/ogg': ['ogx'],
+              'application/omdoc+xml': ['omdoc'],
+              'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'],
+              'application/oxps': ['oxps'],
+              'application/p2p-overlay+xml': ['relo'],
+              'application/patch-ops-error+xml': ['xer'],
+              'application/pdf': ['pdf'],
+              'application/pgp-encrypted': ['pgp'],
+              'application/pgp-signature': ['asc', 'sig'],
+              'application/pics-rules': ['prf'],
+              'application/pkcs10': ['p10'],
+              'application/pkcs7-mime': ['p7m', 'p7c'],
+              'application/pkcs7-signature': ['p7s'],
+              'application/pkcs8': ['p8'],
+              'application/pkix-attr-cert': ['ac'],
+              'application/pkix-cert': ['cer'],
+              'application/pkix-crl': ['crl'],
+              'application/pkix-pkipath': ['pkipath'],
+              'application/pkixcmp': ['pki'],
+              'application/pls+xml': ['pls'],
+              'application/postscript': ['ai', 'eps', 'ps'],
+              'application/provenance+xml': ['provx'],
+              'application/pskc+xml': ['pskcxml'],
+              'application/raml+yaml': ['raml'],
+              'application/rdf+xml': ['rdf', 'owl'],
+              'application/reginfo+xml': ['rif'],
+              'application/relax-ng-compact-syntax': ['rnc'],
+              'application/resource-lists+xml': ['rl'],
+              'application/resource-lists-diff+xml': ['rld'],
+              'application/rls-services+xml': ['rs'],
+              'application/route-apd+xml': ['rapd'],
+              'application/route-s-tsid+xml': ['sls'],
+              'application/route-usd+xml': ['rusd'],
+              'application/rpki-ghostbusters': ['gbr'],
+              'application/rpki-manifest': ['mft'],
+              'application/rpki-roa': ['roa'],
+              'application/rsd+xml': ['rsd'],
+              'application/rss+xml': ['rss'],
+              'application/rtf': ['rtf'],
+              'application/sbml+xml': ['sbml'],
+              'application/scvp-cv-request': ['scq'],
+              'application/scvp-cv-response': ['scs'],
+              'application/scvp-vp-request': ['spq'],
+              'application/scvp-vp-response': ['spp'],
+              'application/sdp': ['sdp'],
+              'application/senml+xml': ['senmlx'],
+              'application/sensml+xml': ['sensmlx'],
+              'application/set-payment-initiation': ['setpay'],
+              'application/set-registration-initiation': ['setreg'],
+              'application/shf+xml': ['shf'],
+              'application/sieve': ['siv', 'sieve'],
+              'application/smil+xml': ['smi', 'smil'],
+              'application/sparql-query': ['rq'],
+              'application/sparql-results+xml': ['srx'],
+              'application/srgs': ['gram'],
+              'application/srgs+xml': ['grxml'],
+              'application/sru+xml': ['sru'],
+              'application/ssdl+xml': ['ssdl'],
+              'application/ssml+xml': ['ssml'],
+              'application/swid+xml': ['swidtag'],
+              'application/tei+xml': ['tei', 'teicorpus'],
+              'application/thraud+xml': ['tfi'],
+              'application/timestamped-data': ['tsd'],
+              'application/toml': ['toml'],
+              'application/trig': ['trig'],
+              'application/ttml+xml': ['ttml'],
+              'application/ubjson': ['ubj'],
+              'application/urc-ressheet+xml': ['rsheet'],
+              'application/urc-targetdesc+xml': ['td'],
+              'application/voicexml+xml': ['vxml'],
+              'application/wasm': ['wasm'],
+              'application/widget': ['wgt'],
+              'application/winhlp': ['hlp'],
+              'application/wsdl+xml': ['wsdl'],
+              'application/wspolicy+xml': ['wspolicy'],
+              'application/xaml+xml': ['xaml'],
+              'application/xcap-att+xml': ['xav'],
+              'application/xcap-caps+xml': ['xca'],
+              'application/xcap-diff+xml': ['xdf'],
+              'application/xcap-el+xml': ['xel'],
+              'application/xcap-ns+xml': ['xns'],
+              'application/xenc+xml': ['xenc'],
+              'application/xhtml+xml': ['xhtml', 'xht'],
+              'application/xliff+xml': ['xlf'],
+              'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
+              'application/xml-dtd': ['dtd'],
+              'application/xop+xml': ['xop'],
+              'application/xproc+xml': ['xpl'],
+              'application/xslt+xml': ['*xsl', 'xslt'],
+              'application/xspf+xml': ['xspf'],
+              'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
+              'application/yang': ['yang'],
+              'application/yin+xml': ['yin'],
+              'application/zip': ['zip'],
+              'audio/3gpp': ['*3gpp'],
+              'audio/adpcm': ['adp'],
+              'audio/amr': ['amr'],
+              'audio/basic': ['au', 'snd'],
+              'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
+              'audio/mobile-xmf': ['mxmf'],
+              'audio/mp3': ['*mp3'],
+              'audio/mp4': ['m4a', 'mp4a'],
+              'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
+              'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
+              'audio/s3m': ['s3m'],
+              'audio/silk': ['sil'],
+              'audio/wav': ['wav'],
+              'audio/wave': ['*wav'],
+              'audio/webm': ['weba'],
+              'audio/xm': ['xm'],
+              'font/collection': ['ttc'],
+              'font/otf': ['otf'],
+              'font/ttf': ['ttf'],
+              'font/woff': ['woff'],
+              'font/woff2': ['woff2'],
+              'image/aces': ['exr'],
+              'image/apng': ['apng'],
+              'image/avif': ['avif'],
+              'image/bmp': ['bmp'],
+              'image/cgm': ['cgm'],
+              'image/dicom-rle': ['drle'],
+              'image/emf': ['emf'],
+              'image/fits': ['fits'],
+              'image/g3fax': ['g3'],
+              'image/gif': ['gif'],
+              'image/heic': ['heic'],
+              'image/heic-sequence': ['heics'],
+              'image/heif': ['heif'],
+              'image/heif-sequence': ['heifs'],
+              'image/hej2k': ['hej2'],
+              'image/hsj2': ['hsj2'],
+              'image/ief': ['ief'],
+              'image/jls': ['jls'],
+              'image/jp2': ['jp2', 'jpg2'],
+              'image/jpeg': ['jpeg', 'jpg', 'jpe'],
+              'image/jph': ['jph'],
+              'image/jphc': ['jhc'],
+              'image/jpm': ['jpm'],
+              'image/jpx': ['jpx', 'jpf'],
+              'image/jxr': ['jxr'],
+              'image/jxra': ['jxra'],
+              'image/jxrs': ['jxrs'],
+              'image/jxs': ['jxs'],
+              'image/jxsc': ['jxsc'],
+              'image/jxsi': ['jxsi'],
+              'image/jxss': ['jxss'],
+              'image/ktx': ['ktx'],
+              'image/ktx2': ['ktx2'],
+              'image/png': ['png'],
+              'image/sgi': ['sgi'],
+              'image/svg+xml': ['svg', 'svgz'],
+              'image/t38': ['t38'],
+              'image/tiff': ['tif', 'tiff'],
+              'image/tiff-fx': ['tfx'],
+              'image/webp': ['webp'],
+              'image/wmf': ['wmf'],
+              'message/disposition-notification': ['disposition-notification'],
+              'message/global': ['u8msg'],
+              'message/global-delivery-status': ['u8dsn'],
+              'message/global-disposition-notification': ['u8mdn'],
+              'message/global-headers': ['u8hdr'],
+              'message/rfc822': ['eml', 'mime'],
+              'model/3mf': ['3mf'],
+              'model/gltf+json': ['gltf'],
+              'model/gltf-binary': ['glb'],
+              'model/iges': ['igs', 'iges'],
+              'model/mesh': ['msh', 'mesh', 'silo'],
+              'model/mtl': ['mtl'],
+              'model/obj': ['obj'],
+              'model/step+xml': ['stpx'],
+              'model/step+zip': ['stpz'],
+              'model/step-xml+zip': ['stpxz'],
+              'model/stl': ['stl'],
+              'model/vrml': ['wrl', 'vrml'],
+              'model/x3d+binary': ['*x3db', 'x3dbz'],
+              'model/x3d+fastinfoset': ['x3db'],
+              'model/x3d+vrml': ['*x3dv', 'x3dvz'],
+              'model/x3d+xml': ['x3d', 'x3dz'],
+              'model/x3d-vrml': ['x3dv'],
+              'text/cache-manifest': ['appcache', 'manifest'],
+              'text/calendar': ['ics', 'ifb'],
+              'text/coffeescript': ['coffee', 'litcoffee'],
+              'text/css': ['css'],
+              'text/csv': ['csv'],
+              'text/html': ['html', 'htm', 'shtml'],
+              'text/jade': ['jade'],
+              'text/jsx': ['jsx'],
+              'text/less': ['less'],
+              'text/markdown': ['markdown', 'md'],
+              'text/mathml': ['mml'],
+              'text/mdx': ['mdx'],
+              'text/n3': ['n3'],
+              'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
+              'text/richtext': ['rtx'],
+              'text/rtf': ['*rtf'],
+              'text/sgml': ['sgml', 'sgm'],
+              'text/shex': ['shex'],
+              'text/slim': ['slim', 'slm'],
+              'text/spdx': ['spdx'],
+              'text/stylus': ['stylus', 'styl'],
+              'text/tab-separated-values': ['tsv'],
+              'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
+              'text/turtle': ['ttl'],
+              'text/uri-list': ['uri', 'uris', 'urls'],
+              'text/vcard': ['vcard'],
+              'text/vtt': ['vtt'],
+              'text/xml': ['*xml'],
+              'text/yaml': ['yaml', 'yml'],
+              'video/3gpp': ['3gp', '3gpp'],
+              'video/3gpp2': ['3g2'],
+              'video/h261': ['h261'],
+              'video/h263': ['h263'],
+              'video/h264': ['h264'],
+              'video/iso.segment': ['m4s'],
+              'video/jpeg': ['jpgv'],
+              'video/jpm': ['*jpm', 'jpgm'],
+              'video/mj2': ['mj2', 'mjp2'],
+              'video/mp2t': ['ts'],
+              'video/mp4': ['mp4', 'mp4v', 'mpg4'],
+              'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
+              'video/ogg': ['ogv'],
+              'video/quicktime': ['qt', 'mov'],
+              'video/webm': ['webm']
+            };
+          },
+          {}
+        ],
+        361: [
+          function (e, t, r) {
+            var s = 864e5;
+            function i(e, t, r, n) {
+              t = 1.5 * r <= t;
+              return Math.round(e / r) + ' ' + n + (t ? 's' : '');
+            }
+            t.exports = function (e, t) {
+              t = t || {};
+              var r = typeof e;
+              if (!('string' == r && 0 < e.length)) {
+                if ('number' == r && isFinite(e))
+                  return (
+                    t.long
+                      ? function (e) {
+                          var t = Math.abs(e);
+                          if (s <= t) return i(e, t, s, 'day');
+                          if (36e5 <= t) return i(e, t, 36e5, 'hour');
+                          if (6e4 <= t) return i(e, t, 6e4, 'minute');
+                          if (1e3 <= t) return i(e, t, 1e3, 'second');
+                          return e + ' ms';
+                        }
+                      : function (e) {
+                          var t = Math.abs(e);
+                          if (s <= t) return Math.round(e / s) + 'd';
+                          if (36e5 <= t) return Math.round(e / 36e5) + 'h';
+                          if (6e4 <= t) return Math.round(e / 6e4) + 'm';
+                          if (1e3 <= t) return Math.round(e / 1e3) + 's';
+                          return e + 'ms';
+                        }
+                  )(e);
+                throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(e));
+              }
+              r = e;
+              if (!(100 < (r = String(r)).length)) {
+                r =
+                  /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
+                    r
+                  );
+                if (r) {
+                  var n = parseFloat(r[1]);
+                  switch ((r[2] || 'ms').toLowerCase()) {
+                    case 'years':
+                    case 'year':
+                    case 'yrs':
+                    case 'yr':
+                    case 'y':
+                      return 315576e5 * n;
+                    case 'weeks':
+                    case 'week':
+                    case 'w':
+                      return 6048e5 * n;
+                    case 'days':
+                    case 'day':
+                    case 'd':
+                      return n * s;
+                    case 'hours':
+                    case 'hour':
+                    case 'hrs':
+                    case 'hr':
+                    case 'h':
+                      return 36e5 * n;
+                    case 'minutes':
+                    case 'minute':
+                    case 'mins':
+                    case 'min':
+                    case 'm':
+                      return 6e4 * n;
+                    case 'seconds':
+                    case 'second':
+                    case 'secs':
+                    case 'sec':
+                    case 's':
+                      return 1e3 * n;
+                    case 'milliseconds':
+                    case 'millisecond':
+                    case 'msecs':
+                    case 'msec':
+                    case 'ms':
+                      return n;
+                    default:
+                      return;
+                  }
+                }
+              }
+            };
+          },
+          {}
+        ],
+        362: [
+          function (e, t, r) {
+            'use strict';
+            var c = Object.getOwnPropertySymbols,
+              l = Object.prototype.hasOwnProperty,
+              u = Object.prototype.propertyIsEnumerable;
+            t.exports = (function () {
+              try {
+                if (!Object.assign) return;
+                var e = new String('abc');
+                if (((e[5] = 'de'), '5' === Object.getOwnPropertyNames(e)[0])) return;
+                for (var t = {}, r = 0; r < 10; r++) t['_' + String.fromCharCode(r)] = r;
+                if (
+                  '0123456789' !==
+                  Object.getOwnPropertyNames(t)
+                    .map(function (e) {
+                      return t[e];
+                    })
+                    .join('')
+                )
+                  return;
+                var n = {};
+                return (
+                  'abcdefghijklmnopqrst'.split('').forEach(function (e) {
+                    n[e] = e;
+                  }),
+                  'abcdefghijklmnopqrst' !== Object.keys(Object.assign({}, n)).join('') ? void 0 : 1
+                );
+              } catch (e) {
+                return;
+              }
+            })()
+              ? Object.assign
+              : function (e, t) {
+                  for (
+                    var r,
+                      n = (function (e) {
+                        if (null == e) throw new TypeError('Object.assign cannot be called with null or undefined');
+                        return Object(e);
+                      })(e),
+                      s = 1;
+                    s < arguments.length;
+                    s++
+                  ) {
+                    for (var i in (r = Object(arguments[s]))) l.call(r, i) && (n[i] = r[i]);
+                    if (c) for (var o = c(r), a = 0; a < o.length; a++) u.call(r, o[a]) && (n[o[a]] = r[o[a]]);
+                  }
+                  return n;
+                };
+          },
+          {}
+        ],
+        363: [
+          function (e, t, l) {
+            !function (o) {
+              !function () {
+                function s(e, t) {
+                  for (var r = 0, n = e.length - 1; 0 <= n; n--) {
+                    var s = e[n];
+                    '.' === s ? e.splice(n, 1) : '..' === s ? (e.splice(n, 1), r++) : r && (e.splice(n, 1), r--);
+                  }
+                  if (t) for (; r--; ) e.unshift('..');
+                  return e;
+                }
+                function i(e, t) {
+                  if (e.filter) return e.filter(t);
+                  for (var r = [], n = 0; n < e.length; n++) t(e[n], n, e) && r.push(e[n]);
+                  return r;
+                }
+                (l.resolve = function () {
+                  for (var e = '', t = !1, r = arguments.length - 1; -1 <= r && !t; r--) {
+                    var n = 0 <= r ? arguments[r] : o.cwd();
+                    if ('string' != typeof n) throw new TypeError('Arguments to path.resolve must be strings');
+                    n && ((e = n + '/' + e), (t = '/' === n.charAt(0)));
+                  }
+                  return (
+                    (t ? '/' : '') +
+                      (e = s(
+                        i(e.split('/'), function (e) {
+                          return !!e;
+                        }),
+                        !t
+                      ).join('/')) || '.'
+                  );
+                }),
+                  (l.normalize = function (e) {
+                    var t = l.isAbsolute(e),
+                      r = '/' === n(e, -1);
+                    return (
+                      (e =
+                        (e = s(
+                          i(e.split('/'), function (e) {
+                            return !!e;
+                          }),
+                          !t
+                        ).join('/')) || t
+                          ? e
+                          : '.') &&
+                        r &&
+                        (e += '/'),
+                      (t ? '/' : '') + e
+                    );
+                  }),
+                  (l.isAbsolute = function (e) {
+                    return '/' === e.charAt(0);
+                  }),
+                  (l.join = function () {
+                    var e = Array.prototype.slice.call(arguments, 0);
+                    return l.normalize(
+                      i(e, function (e, t) {
+                        if ('string' != typeof e) throw new TypeError('Arguments to path.join must be strings');
+                        return e;
+                      }).join('/')
+                    );
+                  }),
+                  (l.relative = function (e, t) {
+                    function r(e) {
+                      for (var t = 0; t < e.length && '' === e[t]; t++);
+                      for (var r = e.length - 1; 0 <= r && '' === e[r]; r--);
+                      return r < t ? [] : e.slice(t, r - t + 1);
+                    }
+                    (e = l.resolve(e).substr(1)), (t = l.resolve(t).substr(1));
+                    for (
+                      var n = r(e.split('/')), s = r(t.split('/')), i = Math.min(n.length, s.length), o = i, a = 0;
+                      a < i;
+                      a++
+                    )
+                      if (n[a] !== s[a]) {
+                        o = a;
+                        break;
+                      }
+                    for (var c = [], a = o; a < n.length; a++) c.push('..');
+                    return (c = c.concat(s.slice(o))).join('/');
+                  }),
+                  (l.sep = '/'),
+                  (l.delimiter = ':'),
+                  (l.dirname = function (e) {
+                    if (('string' != typeof e && (e += ''), 0 === e.length)) return '.';
+                    for (var t = 47 === e.charCodeAt(0), r = -1, n = !0, s = e.length - 1; 1 <= s; --s)
+                      if (47 === e.charCodeAt(s)) {
+                        if (!n) {
+                          r = s;
+                          break;
+                        }
+                      } else n = !1;
+                    return -1 === r ? (t ? '/' : '.') : t && 1 === r ? '/' : e.slice(0, r);
+                  }),
+                  (l.basename = function (e, t) {
+                    e = (function (e) {
+                      'string' != typeof e && (e += '');
+                      for (var t = 0, r = -1, n = !0, s = e.length - 1; 0 <= s; --s)
+                        if (47 === e.charCodeAt(s)) {
+                          if (!n) {
+                            t = s + 1;
+                            break;
+                          }
+                        } else -1 === r && ((n = !1), (r = s + 1));
+                      return -1 === r ? '' : e.slice(t, r);
+                    })(e);
+                    return (e = t && e.substr(-1 * t.length) === t ? e.substr(0, e.length - t.length) : e);
+                  }),
+                  (l.extname = function (e) {
+                    'string' != typeof e && (e += '');
+                    for (var t = -1, r = 0, n = -1, s = !0, i = 0, o = e.length - 1; 0 <= o; --o) {
+                      var a = e.charCodeAt(o);
+                      if (47 === a) {
+                        if (s) continue;
+                        r = o + 1;
+                        break;
+                      }
+                      -1 === n && ((s = !1), (n = o + 1)),
+                        46 === a ? (-1 === t ? (t = o) : 1 !== i && (i = 1)) : -1 !== t && (i = -1);
+                    }
+                    return -1 === t || -1 === n || 0 === i || (1 === i && t === n - 1 && t === r + 1)
+                      ? ''
+                      : e.slice(t, n);
+                  });
+                var n =
+                  'b' === 'ab'.substr(-1)
+                    ? function (e, t, r) {
+                        return e.substr(t, r);
+                      }
+                    : function (e, t, r) {
+                        return t < 0 && (t = e.length + t), e.substr(t, r);
+                      };
+              }.call(this);
+            }.call(this, e('_process'));
+          },
+          { _process: 441 }
+        ],
+        364: [
+          function (e, o, c) {
+            !function (i) {
+              !function () {
+                !function () {
+                  'use strict';
+                  var e = { function: !0, object: !0 },
+                    D = (e[typeof window] && window) || this,
+                    r = e[typeof c] && c,
+                    e = e[typeof o] && o && !o.nodeType && o,
+                    t = r && e && 'object' == typeof i && i,
+                    a = (!t || (t.global !== t && t.window !== t && t.self !== t) || (D = t), Math.pow(2, 53) - 1),
+                    I = /\bOpera/,
+                    t = Object.prototype,
+                    n = t.hasOwnProperty,
+                    C = t.toString;
+                  function s(e) {
+                    return (e = String(e)).charAt(0).toUpperCase() + e.slice(1);
+                  }
+                  function N(e) {
+                    return (e = B(e)), /^(?:webOS|i(?:OS|P))/.test(e) ? e : s(e);
+                  }
+                  function R(e, t) {
+                    for (var r in e) n.call(e, r) && t(e[r], r, e);
+                  }
+                  function P(e) {
+                    return null == e ? s(e) : C.call(e).slice(8, -1);
+                  }
+                  function M(e) {
+                    return String(e).replace(/([ -])(?!$)/g, '$1?');
+                  }
+                  function L(r, n) {
+                    var s = null,
+                      e = r,
+                      t = function (e, t) {
+                        s = n(s, e, t, r);
+                      },
+                      i = -1,
+                      o = e ? e.length : 0;
+                    if ('number' == typeof o && -1 < o && o <= a) for (; ++i < o; ) t(e[i], i, e);
+                    else R(e, t);
+                    return s;
+                  }
+                  function B(e) {
+                    return String(e).replace(/^ +| +$/g, '');
+                  }
+                  function q(i) {
+                    var t,
+                      r,
+                      e,
+                      n,
+                      s = D,
+                      o = i && 'object' == typeof i && 'String' != P(i),
+                      a = (o && ((s = i), (i = null)), s.navigator || {}),
+                      c = a.userAgent || '',
+                      l =
+                        ((i = i || c), o ? !!a.likeChrome : /\bChrome\b/.test(i) && !/internal|\n/i.test(C.toString())),
+                      u = 'Object',
+                      p = o ? u : 'ScriptBridgingProxyObject',
+                      f = o ? u : 'Environment',
+                      d = o && s.java ? 'JavaPackage' : P(s.java),
+                      u = o ? u : 'RuntimeObject',
+                      d = /\bJava/.test(d) && s.java,
+                      f = d && P(s.environment) == f,
+                      h = d ? 'a' : '\u03b1',
+                      m = d ? 'b' : '\u03b2',
+                      y = s.document || {},
+                      b = s.operamini || s.opera,
+                      o = I.test((o = o && b ? b['[[Class]]'] : P(b))) ? o : (b = null),
+                      g = i,
+                      v = [],
+                      j = null,
+                      c = i == c,
+                      w = c && b && 'function' == typeof b.version && b.version(),
+                      x = L(
+                        [
+                          { label: 'EdgeHTML', pattern: 'Edge' },
+                          'Trident',
+                          { label: 'WebKit', pattern: 'AppleWebKit' },
+                          'iCab',
+                          'Presto',
+                          'NetFront',
+                          'Tasman',
+                          'KHTML',
+                          'Gecko'
+                        ],
+                        function (e, t) {
+                          return e || (RegExp('\\b' + (t.pattern || M(t)) + '\\b', 'i').exec(i) && (t.label || t));
+                        }
+                      ),
+                      T = L(
+                        [
+                          'Adobe AIR',
+                          'Arora',
+                          'Avant Browser',
+                          'Breach',
+                          'Camino',
+                          'Electron',
+                          'Epiphany',
+                          'Fennec',
+                          'Flock',
+                          'Galeon',
+                          'GreenBrowser',
+                          'iCab',
+                          'Iceweasel',
+                          'K-Meleon',
+                          'Konqueror',
+                          'Lunascape',
+                          'Maxthon',
+                          { label: 'Microsoft Edge', pattern: '(?:Edge|Edg|EdgA|EdgiOS)' },
+                          'Midori',
+                          'Nook Browser',
+                          'PaleMoon',
+                          'PhantomJS',
+                          'Raven',
+                          'Rekonq',
+                          'RockMelt',
+                          { label: 'Samsung Internet', pattern: 'SamsungBrowser' },
+                          'SeaMonkey',
+                          { label: 'Silk', pattern: '(?:Cloud9|Silk-Accelerated)' },
+                          'Sleipnir',
+                          'SlimBrowser',
+                          { label: 'SRWare Iron', pattern: 'Iron' },
+                          'Sunrise',
+                          'Swiftfox',
+                          'Vivaldi',
+                          'Waterfox',
+                          'WebPositive',
+                          { label: 'Yandex Browser', pattern: 'YaBrowser' },
+                          { label: 'UC Browser', pattern: 'UCBrowser' },
+                          'Opera Mini',
+                          { label: 'Opera Mini', pattern: 'OPiOS' },
+                          'Opera',
+                          { label: 'Opera', pattern: 'OPR' },
+                          'Chromium',
+                          'Chrome',
+                          { label: 'Chrome', pattern: '(?:HeadlessChrome)' },
+                          { label: 'Chrome Mobile', pattern: '(?:CriOS|CrMo)' },
+                          { label: 'Firefox', pattern: '(?:Firefox|Minefield)' },
+                          { label: 'Firefox for iOS', pattern: 'FxiOS' },
+                          { label: 'IE', pattern: 'IEMobile' },
+                          { label: 'IE', pattern: 'MSIE' },
+                          'Safari'
+                        ],
+                        function (e, t) {
+                          return e || (RegExp('\\b' + (t.pattern || M(t)) + '\\b', 'i').exec(i) && (t.label || t));
+                        }
+                      ),
+                      k = S([
+                        { label: 'BlackBerry', pattern: 'BB10' },
+                        'BlackBerry',
+                        { label: 'Galaxy S', pattern: 'GT-I9000' },
+                        { label: 'Galaxy S2', pattern: 'GT-I9100' },
+                        { label: 'Galaxy S3', pattern: 'GT-I9300' },
+                        { label: 'Galaxy S4', pattern: 'GT-I9500' },
+                        { label: 'Galaxy S5', pattern: 'SM-G900' },
+                        { label: 'Galaxy S6', pattern: 'SM-G920' },
+                        { label: 'Galaxy S6 Edge', pattern: 'SM-G925' },
+                        { label: 'Galaxy S7', pattern: 'SM-G930' },
+                        { label: 'Galaxy S7 Edge', pattern: 'SM-G935' },
+                        'Google TV',
+                        'Lumia',
+                        'iPad',
+                        'iPod',
+                        'iPhone',
+                        'Kindle',
+                        { label: 'Kindle Fire', pattern: '(?:Cloud9|Silk-Accelerated)' },
+                        'Nexus',
+                        'Nook',
+                        'PlayBook',
+                        'PlayStation Vita',
+                        'PlayStation',
+                        'TouchPad',
+                        'Transformer',
+                        { label: 'Wii U', pattern: 'WiiU' },
+                        'Wii',
+                        'Xbox One',
+                        { label: 'Xbox 360', pattern: 'Xbox' },
+                        'Xoom'
+                      ]),
+                      E = L(
+                        {
+                          Apple: { iPad: 1, iPhone: 1, iPod: 1 },
+                          Alcatel: {},
+                          Archos: {},
+                          Amazon: { Kindle: 1, 'Kindle Fire': 1 },
+                          Asus: { Transformer: 1 },
+                          'Barnes & Noble': { Nook: 1 },
+                          BlackBerry: { PlayBook: 1 },
+                          Google: { 'Google TV': 1, Nexus: 1 },
+                          HP: { TouchPad: 1 },
+                          HTC: {},
+                          Huawei: {},
+                          Lenovo: {},
+                          LG: {},
+                          Microsoft: { Xbox: 1, 'Xbox One': 1 },
+                          Motorola: { Xoom: 1 },
+                          Nintendo: { 'Wii U': 1, Wii: 1 },
+                          Nokia: { Lumia: 1 },
+                          Oppo: {},
+                          Samsung: { 'Galaxy S': 1, 'Galaxy S2': 1, 'Galaxy S3': 1, 'Galaxy S4': 1 },
+                          Sony: { PlayStation: 1, 'PlayStation Vita': 1 },
+                          Xiaomi: { Mi: 1, Redmi: 1 }
+                        },
+                        function (e, t, r) {
+                          return (
+                            e ||
+                            ((t[k] ||
+                              t[/^[a-z]+(?: +[a-z]+\b)*/i.exec(k)] ||
+                              RegExp('\\b' + M(r) + '(?:\\b|\\w*\\d)', 'i').exec(i)) &&
+                              r)
+                          );
+                        }
+                      ),
+                      _ = L(
+                        [
+                          'Windows Phone',
+                          'KaiOS',
+                          'Android',
+                          'CentOS',
+                          { label: 'Chrome OS', pattern: 'CrOS' },
+                          'Debian',
+                          { label: 'DragonFly BSD', pattern: 'DragonFly' },
+                          'Fedora',
+                          'FreeBSD',
+                          'Gentoo',
+                          'Haiku',
+                          'Kubuntu',
+                          'Linux Mint',
+                          'OpenBSD',
+                          'Red Hat',
+                          'SuSE',
+                          'Ubuntu',
+                          'Xubuntu',
+                          'Cygwin',
+                          'Symbian OS',
+                          'hpwOS',
+                          'webOS ',
+                          'webOS',
+                          'Tablet OS',
+                          'Tizen',
+                          'Linux',
+                          'Mac OS X',
+                          'Macintosh',
+                          'Mac',
+                          'Windows 98;',
+                          'Windows '
+                        ],
+                        function (e, t) {
+                          var r,
+                            n,
+                            s = t.pattern || M(t);
+                          return (
+                            !e &&
+                              (e = RegExp('\\b' + s + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(i)) &&
+                              ((r = e),
+                              (s = s),
+                              (t = t.label || t),
+                              (n = {
+                                '10.0': '10',
+                                6.4: '10 Technical Preview',
+                                6.3: '8.1',
+                                6.2: '8',
+                                6.1: 'Server 2008 R2 / 7',
+                                '6.0': 'Server 2008 / Vista',
+                                5.2: 'Server 2003 / XP 64-bit',
+                                5.1: 'XP',
+                                5.01: '2000 SP1',
+                                '5.0': '2000',
+                                '4.0': 'NT',
+                                '4.90': 'ME'
+                              }),
+                              s &&
+                                t &&
+                                /^Win/i.test(r) &&
+                                !/^Windows Phone /i.test(r) &&
+                                (n = n[/[\d.]+$/.exec(r)]) &&
+                                (r = 'Windows ' + n),
+                              (r = String(r)),
+                              (e = r =
+                                N(
+                                  (r = s && t ? r.replace(RegExp(s, 'i'), t) : r)
+                                    .replace(/ ce$/i, ' CE')
+                                    .replace(/\bhpw/i, 'web')
+                                    .replace(/\bMacintosh\b/, 'Mac OS')
+                                    .replace(/_PowerPC\b/i, ' OS')
+                                    .replace(/\b(OS X) [^ \d]+/i, '$1')
+                                    .replace(/\bMac (OS X)\b/, '$1')
+                                    .replace(/\/(\d)/, ' $1')
+                                    .replace(/_/g, '.')
+                                    .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '')
+                                    .replace(/\bx86\.64\b/gi, 'x86_64')
+                                    .replace(/\b(Windows Phone) OS\b/, '$1')
+                                    .replace(/\b(Chrome OS \w+) [\d.]+\b/, '$1')
+                                    .split(' on ')[0]
+                                ))),
+                            e
+                          );
+                        }
+                      );
+                    function S(e) {
+                      return L(e, function (e, t) {
+                        var r = t.pattern || M(t);
+                        return (
+                          !e &&
+                            (e =
+                              RegExp('\\b' + r + ' *\\d+[.\\w_]*', 'i').exec(i) ||
+                              RegExp('\\b' + r + ' *\\w+-[\\w]*', 'i').exec(i) ||
+                              RegExp('\\b' + r + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(i)) &&
+                            ((e = String(t.label && !RegExp(r, 'i').test(t.label) ? t.label : e).split('/'))[1] &&
+                              !/[\d.]+/.test(e[0]) &&
+                              (e[0] += ' ' + e[1]),
+                            (t = t.label || t),
+                            (e = N(
+                              e[0]
+                                .replace(RegExp(r, 'i'), t)
+                                .replace(RegExp('; *(?:' + t + '[_-])?', 'i'), ' ')
+                                .replace(RegExp('(' + t + ')[-_.]?(\\w)', 'i'), '$1 $2')
+                            ))),
+                          e
+                        );
+                      });
+                    }
+                    function O(e) {
+                      return L(e, function (e, t) {
+                        return (
+                          e ||
+                          (RegExp(t + '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(i) ||
+                            0)[1] ||
+                          null
+                        );
+                      });
+                    }
+                    if (
+                      ((x = x && [x]),
+                      /\bAndroid\b/.test(_) &&
+                        !k &&
+                        (t = /\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(i)) &&
+                        (k = B(t[1]).replace(/^[a-z]{2}-[a-z]{2};\s*/i, '') || null),
+                      E && !k
+                        ? (k = S([E]))
+                        : E &&
+                          k &&
+                          (k = k
+                            .replace(RegExp('^(' + M(E) + ')[-_.\\s]', 'i'), E + ' ')
+                            .replace(RegExp('^(' + M(E) + ')[-_.]?(\\w)', 'i'), E + ' $2')),
+                      (t = /\bGoogle TV\b/.exec(k)) && (k = t[0]),
+                      /\bSimulator\b/i.test(i) && (k = (k ? k + ' ' : '') + 'Simulator'),
+                      'Opera Mini' == T && /\bOPiOS\b/.test(i) && v.push('running in Turbo/Uncompressed mode'),
+                      'IE' == T && /\blike iPhone OS\b/.test(i)
+                        ? ((E = (t = q(i.replace(/like iPhone OS/, ''))).manufacturer), (k = t.product))
+                        : /^iP/.test(k)
+                        ? ((T = T || 'Safari'),
+                          (_ = 'iOS' + ((t = / OS ([\d_]+)/i.exec(i)) ? ' ' + t[1].replace(/_/g, '.') : '')))
+                        : 'Konqueror' == T && /^Linux\b/i.test(_)
+                        ? (_ = 'Kubuntu')
+                        : (E &&
+                            'Google' != E &&
+                            ((/Chrome/.test(T) && !/\bMobile Safari\b/i.test(i)) || /\bVita\b/.test(k))) ||
+                          (/\bAndroid\b/.test(_) && /^Chrome/.test(T) && /\bVersion\//i.test(i))
+                        ? ((T = 'Android Browser'), (_ = /\bAndroid\b/.test(_) ? _ : 'Android'))
+                        : 'Silk' == T
+                        ? (/\bMobi/i.test(i) || ((_ = 'Android'), v.unshift('desktop mode')),
+                          /Accelerated *= *true/i.test(i) && v.unshift('accelerated'))
+                        : 'UC Browser' == T && /\bUCWEB\b/.test(i)
+                        ? v.push('speed mode')
+                        : 'PaleMoon' == T && (t = /\bFirefox\/([\d.]+)\b/.exec(i))
+                        ? v.push('identifying as Firefox ' + t[1])
+                        : 'Firefox' == T && (t = /\b(Mobile|Tablet|TV)\b/i.exec(i))
+                        ? ((_ = _ || 'Firefox OS'), (k = k || t[1]))
+                        : !T || (t = !/\bMinefield\b/i.test(i) && /\b(?:Firefox|Safari)\b/.exec(T))
+                        ? (T && !k && /[\/,]|^[^(]+?\)/.test(i.slice(i.indexOf(t + '/') + 8)) && (T = null),
+                          (t = k || E || _) &&
+                            (k || E || /\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(_)) &&
+                            (T = /[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(_) ? _ : t) + ' Browser'))
+                        : 'Electron' == T && (t = (/\bChrome\/([\d.]+)\b/.exec(i) || 0)[1]) && v.push('Chromium ' + t),
+                      (w =
+                        w ||
+                        O([
+                          '(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)',
+                          'Version',
+                          M(T),
+                          '(?:Firefox|Minefield|NetFront)'
+                        ])),
+                      (t =
+                        ('iCab' == x && 3 < parseFloat(w)
+                          ? 'WebKit'
+                          : /\bOpera\b/.test(T) && (/\bOPR\b/.test(i) ? 'Blink' : 'Presto')) ||
+                        (/\b(?:Midori|Nook|Safari)\b/i.test(i) && !/^(?:Trident|EdgeHTML)$/.test(x) && 'WebKit') ||
+                        (!x && /\bMSIE\b/i.test(i) && ('Mac OS' == _ ? 'Tasman' : 'Trident')) ||
+                        ('WebKit' == x && /\bPlayStation\b(?! Vita\b)/i.test(T) && 'NetFront')) && (x = [t]),
+                      'IE' == T && (t = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(i) || 0)[1])
+                        ? ((T += ' Mobile'),
+                          (_ = 'Windows Phone ' + (/\+$/.test(t) ? t : t + '.x')),
+                          v.unshift('desktop mode'))
+                        : /\bWPDesktop\b/i.test(i)
+                        ? ((T = 'IE Mobile'),
+                          (_ = 'Windows Phone 8.x'),
+                          v.unshift('desktop mode'),
+                          (w = w || (/\brv:([\d.]+)/.exec(i) || 0)[1]))
+                        : 'IE' != T &&
+                          'Trident' == x &&
+                          (t = /\brv:([\d.]+)/.exec(i)) &&
+                          (T && v.push('identifying as ' + T + (w ? ' ' + w : '')), (T = 'IE'), (w = t[1])),
+                      c)
+                    ) {
+                      if (
+                        ((n = 'global'),
+                        (A = null != (e = s) ? typeof e[n] : 'number'),
+                        /^(?:boolean|number|string|undefined)$/.test(A) || ('object' == A && !e[n]))
+                      )
+                        P((t = s.runtime)) == p
+                          ? ((T = 'Adobe AIR'), (_ = t.flash.system.Capabilities.os))
+                          : P((t = s.phantom)) == u
+                          ? ((T = 'PhantomJS'),
+                            (w = (t = t.version || null) && t.major + '.' + t.minor + '.' + t.patch))
+                          : 'number' == typeof y.documentMode && (t = /\bTrident\/(\d+)/i.exec(i))
+                          ? ((w = [w, y.documentMode]),
+                            (t = +t[1] + 4) != w[1] && (v.push('IE ' + w[1] + ' mode'), x && (x[1] = ''), (w[1] = t)),
+                            (w = 'IE' == T ? String(w[1].toFixed(1)) : w[0]))
+                          : 'number' == typeof y.documentMode &&
+                            /^(?:Chrome|Firefox)\b/.test(T) &&
+                            (v.push('masking as ' + T + ' ' + w),
+                            (T = 'IE'),
+                            (w = '11.0'),
+                            (x = ['Trident']),
+                            (_ = 'Windows'));
+                      else if (
+                        (d &&
+                          ((g = (t = d.lang.System).getProperty('os.arch')),
+                          (_ = _ || t.getProperty('os.name') + ' ' + t.getProperty('os.version'))),
+                        f)
+                      ) {
+                        try {
+                          (w = s.require('ringo/engine').version.join('.')), (T = 'RingoJS');
+                        } catch (e) {
+                          (t = s.system) &&
+                            t.global.system == s.system &&
+                            ((T = 'Narwhal'), (_ = _ || t[0].os || null));
+                        }
+                        T = T || 'Rhino';
+                      } else
+                        'object' == typeof s.process &&
+                          !s.process.browser &&
+                          (t = s.process) &&
+                          ('object' == typeof t.versions &&
+                            ('string' == typeof t.versions.electron
+                              ? (v.push('Node ' + t.versions.node), (T = 'Electron'), (w = t.versions.electron))
+                              : 'string' == typeof t.versions.nw &&
+                                (v.push('Chromium ' + w, 'Node ' + t.versions.node),
+                                (T = 'NW.js'),
+                                (w = t.versions.nw))),
+                          T ||
+                            ((T = 'Node.js'),
+                            (g = t.arch),
+                            (_ = t.platform),
+                            (w = (w = /[\d.]+/.exec(t.version)) ? w[0] : null)));
+                      _ = _ && N(_);
+                    }
+                    if (
+                      (w &&
+                        (t =
+                          /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(w) ||
+                          /(?:alpha|beta)(?: ?\d)?/i.exec(i + ';' + (c && a.appMinorVersion)) ||
+                          (/\bMinefield\b/i.test(i) && 'a')) &&
+                        ((j = /b/i.test(t) ? 'beta' : 'alpha'),
+                        (w = w.replace(RegExp(t + '\\+?$'), '') + ('beta' == j ? m : h) + (/\d+\+?/.exec(t) || ''))),
+                      'Fennec' == T || ('Firefox' == T && /\b(?:Android|Firefox OS|KaiOS)\b/.test(_)))
+                    )
+                      T = 'Firefox Mobile';
+                    else if ('Maxthon' == T && w) w = w.replace(/\.[\d.]+/, '.x');
+                    else if (/\bXbox\b/i.test(k))
+                      'Xbox 360' == k && (_ = null),
+                        'Xbox 360' == k && /\bIEMobile\b/.test(i) && v.unshift('mobile mode');
+                    else if (
+                      (!/^(?:Chrome|IE|Opera)$/.test(T) && (!T || k || /Browser|Mobi/.test(T))) ||
+                      ('Windows CE' != _ && !/Mobi/i.test(i))
+                    )
+                      if ('IE' == T && c)
+                        try {
+                          null === s.external && v.unshift('platform preview');
+                        } catch (e) {
+                          v.unshift('embedded');
+                        }
+                      else
+                        (/\bBlackBerry\b/.test(k) || /\bBB10\b/.test(i)) &&
+                        (t = (RegExp(k.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(i) || 0)[1] || w)
+                          ? ((_ =
+                              ((t = [t, /BB10/.test(i)])[1] ? ((k = null), (E = 'BlackBerry')) : 'Device Software') +
+                              ' ' +
+                              t[0]),
+                            (w = null))
+                          : this != R &&
+                            'Wii' != k &&
+                            ((c && b) ||
+                              (/Opera/.test(T) && /\b(?:MSIE|Firefox)\b/i.test(i)) ||
+                              ('Firefox' == T && /\bOS X (?:\d+\.){2,}/.test(_)) ||
+                              ('IE' == T &&
+                                ((_ && !/^Win/.test(_) && 5.5 < w) ||
+                                  (/\bWindows XP\b/.test(_) && 8 < w) ||
+                                  (8 == w && !/\bTrident\b/.test(i))))) &&
+                            !I.test((t = q.call(R, i.replace(I, '') + ';'))) &&
+                            t.name &&
+                            ((t = 'ing as ' + t.name + ((t = t.version) ? ' ' + t : '')),
+                            I.test(T)
+                              ? (/\bIE\b/.test(t) && 'Mac OS' == _ && (_ = null), (t = 'identify' + t))
+                              : ((t = 'mask' + t),
+                                (T = o ? N(o.replace(/([a-z])([A-Z])/g, '$1 $2')) : 'Opera'),
+                                /\bIE\b/.test(t) && (_ = null),
+                                c || (w = null)),
+                            (x = ['Presto']),
+                            v.push(t));
+                    else T += ' Mobile';
+                    (t = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(i) || 0)[1]) &&
+                      ((t = [parseFloat(t.replace(/\.(\d)$/, '.0$1')), t]),
+                      'Safari' == T && '+' == t[1].slice(-1)
+                        ? ((T = 'WebKit Nightly'), (j = 'alpha'), (w = t[1].slice(0, -1)))
+                        : (w != t[1] && w != (t[2] = (/\bSafari\/([\d.]+\+?)/i.exec(i) || 0)[1])) || (w = null),
+                      (t[1] = (/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(i) || 0)[1]),
+                      537.36 == t[0] && 537.36 == t[2] && 28 <= parseFloat(t[1]) && 'WebKit' == x && (x = ['Blink']),
+                      (t =
+                        c && (l || t[1])
+                          ? (x && (x[1] = 'like Chrome'),
+                            t[1] ||
+                              ((t = t[0]) < 530
+                                ? 1
+                                : t < 532
+                                ? 2
+                                : t < 532.05
+                                ? 3
+                                : t < 533
+                                ? 4
+                                : t < 534.03
+                                ? 5
+                                : t < 534.07
+                                ? 6
+                                : t < 534.1
+                                ? 7
+                                : t < 534.13
+                                ? 8
+                                : t < 534.16
+                                ? 9
+                                : t < 534.24
+                                ? 10
+                                : t < 534.3
+                                ? 11
+                                : t < 535.01
+                                ? 12
+                                : t < 535.02
+                                ? '13+'
+                                : t < 535.07
+                                ? 15
+                                : t < 535.11
+                                ? 16
+                                : t < 535.19
+                                ? 17
+                                : t < 536.05
+                                ? 18
+                                : t < 536.1
+                                ? 19
+                                : t < 537.01
+                                ? 20
+                                : t < 537.11
+                                ? '21+'
+                                : t < 537.13
+                                ? 23
+                                : t < 537.18
+                                ? 24
+                                : t < 537.24
+                                ? 25
+                                : t < 537.36
+                                ? 26
+                                : 'Blink' != x
+                                ? '27'
+                                : '28'))
+                          : (x && (x[1] = 'like Safari'),
+                            (t = t[0]) < 400
+                              ? 1
+                              : t < 500
+                              ? 2
+                              : t < 526
+                              ? 3
+                              : t < 533
+                              ? 4
+                              : t < 534
+                              ? '4+'
+                              : t < 535
+                              ? 5
+                              : t < 537
+                              ? 6
+                              : t < 538
+                              ? 7
+                              : t < 601
+                              ? 8
+                              : t < 602
+                              ? 9
+                              : t < 604
+                              ? 10
+                              : t < 606
+                              ? 11
+                              : t < 608
+                              ? 12
+                              : '12')),
+                      x && (x[1] += ' ' + (t += 'number' == typeof t ? '.x' : /[.+]/.test(t) ? '' : '+')),
+                      'Safari' == T && (!w || 45 < parseInt(w))
+                        ? (w = t)
+                        : 'Chrome' == T && /\bHeadlessChrome/i.test(i) && v.unshift('headless')),
+                      'Opera' == T && (t = /\bzbov|zvav$/.exec(_))
+                        ? ((T += ' '),
+                          v.unshift('desktop mode'),
+                          'zvav' == t ? ((T += 'Mini'), (w = null)) : (T += 'Mobile'),
+                          (_ = _.replace(RegExp(' *' + t + '$'), '')))
+                        : 'Safari' == T && /\bChrome\b/.exec(x && x[1])
+                        ? (v.unshift('desktop mode'),
+                          (T = 'Chrome Mobile'),
+                          (w = null),
+                          (_ = /\bOS X\b/.test(_) ? ((E = 'Apple'), 'iOS 4.3+') : null))
+                        : /\bSRWare Iron\b/.test(T) && !w && (w = O('Chrome')),
+                      (_ =
+                        w && 0 == w.indexOf((t = /[\d.]+$/.exec(_))) && -1 < i.indexOf('/' + t + '-')
+                          ? B(_.replace(t, ''))
+                          : _) &&
+                        -1 != _.indexOf(T) &&
+                        !RegExp(T + ' OS').test(_) &&
+                        (_ = _.replace(RegExp(' *' + M(T) + ' *'), '')),
+                      x &&
+                        !/\b(?:Avant|Nook)\b/.test(T) &&
+                        (/Browser|Lunascape|Maxthon/.test(T) ||
+                          ('Safari' != T && /^iOS/.test(_) && /\bSafari\b/.test(x[1])) ||
+                          (/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(
+                            T
+                          ) &&
+                            x[1])) &&
+                        (t = x[x.length - 1]) &&
+                        v.push(t),
+                      v.length && (v = ['(' + v.join('; ') + ')']),
+                      E && k && k.indexOf(E) < 0 && v.push('on ' + E),
+                      k && v.push((/^on /.test(v[v.length - 1]) ? '' : 'on ') + k),
+                      _ &&
+                        ((t = / ([\d.+]+)$/.exec(_)),
+                        (r = t && '/' == _.charAt(_.length - t[0].length - 1)),
+                        (_ = {
+                          architecture: 32,
+                          family: t && !r ? _.replace(t[0], '') : _,
+                          version: t ? t[1] : null,
+                          toString: function () {
+                            var e = this.version;
+                            return this.family + (e && !r ? ' ' + e : '') + (64 == this.architecture ? ' 64-bit' : '');
+                          }
+                        })),
+                      (t = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(g)) && !/\bi686\b/i.test(g)
+                        ? (_ && ((_.architecture = 64), (_.family = _.family.replace(RegExp(' *' + t), ''))),
+                          T &&
+                            (/\bWOW64\b/i.test(i) ||
+                              (c && /\w(?:86|32)$/.test(a.cpuClass || a.platform) && !/\bWin64; x64\b/i.test(i))) &&
+                            v.unshift('32-bit'))
+                        : _ && /^OS X/.test(_.family) && 'Chrome' == T && 39 <= parseFloat(w) && (_.architecture = 64),
+                      (i = i || null);
+                    var A = {};
+                    return (
+                      (A.description = i),
+                      (A.layout = x && x[0]),
+                      (A.manufacturer = E),
+                      (A.name = T),
+                      (A.prerelease = j),
+                      (A.product = k),
+                      (A.ua = i),
+                      (A.version = T && w),
+                      (A.os = _ || {
+                        architecture: null,
+                        family: null,
+                        version: null,
+                        toString: function () {
+                          return 'null';
+                        }
+                      }),
+                      (A.parse = q),
+                      (A.toString = function () {
+                        return this.description || '';
+                      }),
+                      A.version && v.unshift(w),
+                      A.name && v.unshift(T),
+                      _ &&
+                        T &&
+                        (_ != String(_).split(' ')[0] || (_ != T.split(' ')[0] && !k)) &&
+                        v.push(k ? '(' + _ + ')' : 'on ' + _),
+                      v.length && (A.description = v.join(' ')),
+                      A
+                    );
+                  }
+                  t = q();
+                  r && e
+                    ? R(t, function (e, t) {
+                        r[t] = e;
+                      })
+                    : (D.platform = t);
+                }.call(this);
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        365: [
+          function (e, t, r) {
+            !function (a) {
+              !function () {
+                'use strict';
+                void 0 === a ||
+                !a.version ||
+                0 === a.version.indexOf('v0.') ||
+                (0 === a.version.indexOf('v1.') && 0 !== a.version.indexOf('v1.8.'))
+                  ? (t.exports = {
+                      nextTick: function (e, t, r, n) {
+                        if ('function' != typeof e) throw new TypeError('"callback" argument must be a function');
+                        var s,
+                          i,
+                          o = arguments.length;
+                        switch (o) {
+                          case 0:
+                          case 1:
+                            return a.nextTick(e);
+                          case 2:
+                            return a.nextTick(function () {
+                              e.call(null, t);
+                            });
+                          case 3:
+                            return a.nextTick(function () {
+                              e.call(null, t, r);
+                            });
+                          case 4:
+                            return a.nextTick(function () {
+                              e.call(null, t, r, n);
+                            });
+                          default:
+                            for (s = new Array(o - 1), i = 0; i < s.length; ) s[i++] = arguments[i];
+                            return a.nextTick(function () {
+                              e.apply(null, s);
+                            });
+                        }
+                      }
+                    })
+                  : (t.exports = a);
+              }.call(this);
+            }.call(this, e('_process'));
+          },
+          { _process: 441 }
+        ],
+        366: [
+          function (e, t, r) {
+            var n,
+              s,
+              t = (t.exports = {});
+            function i() {
+              throw new Error('setTimeout has not been defined');
+            }
+            function o() {
+              throw new Error('clearTimeout has not been defined');
+            }
+            try {
+              n = 'function' == typeof setTimeout ? setTimeout : i;
+            } catch (e) {
+              n = i;
+            }
+            try {
+              s = 'function' == typeof clearTimeout ? clearTimeout : o;
+            } catch (e) {
+              s = o;
+            }
+            function a(t) {
+              if (n === setTimeout) return setTimeout(t, 0);
+              if ((n === i || !n) && setTimeout) return (n = setTimeout)(t, 0);
+              try {
+                return n(t, 0);
+              } catch (e) {
+                try {
+                  return n.call(null, t, 0);
+                } catch (e) {
+                  return n.call(this, t, 0);
+                }
+              }
+            }
+            var c,
+              l = [],
+              u = !1,
+              p = -1;
+            function f() {
+              u && c && ((u = !1), c.length ? (l = c.concat(l)) : (p = -1), l.length && d());
+            }
+            function d() {
+              if (!u) {
+                for (var e = a(f), t = ((u = !0), l.length); t; ) {
+                  for (c = l, l = []; ++p < t; ) c && c[p].run();
+                  (p = -1), (t = l.length);
+                }
+                (c = null),
+                  (u = !1),
+                  !(function (t) {
+                    if (s === clearTimeout) return clearTimeout(t);
+                    if ((s === o || !s) && clearTimeout) return (s = clearTimeout)(t);
+                    try {
+                      s(t);
+                    } catch (e) {
+                      try {
+                        return s.call(null, t);
+                      } catch (e) {
+                        return s.call(this, t);
+                      }
+                    }
+                  })(e);
+              }
+            }
+            function h(e, t) {
+              (this.fun = e), (this.array = t);
+            }
+            function m() {}
+            (t.nextTick = function (e) {
+              var t = new Array(arguments.length - 1);
+              if (1 < arguments.length) for (var r = 1; r < arguments.length; r++) t[r - 1] = arguments[r];
+              l.push(new h(e, t)), 1 !== l.length || u || a(d);
+            }),
+              (h.prototype.run = function () {
+                this.fun.apply(null, this.array);
+              }),
+              (t.title = 'browser'),
+              (t.browser = !0),
+              (t.env = {}),
+              (t.argv = []),
+              (t.version = ''),
+              (t.versions = {}),
+              (t.on = m),
+              (t.addListener = m),
+              (t.once = m),
+              (t.off = m),
+              (t.removeListener = m),
+              (t.removeAllListeners = m),
+              (t.emit = m),
+              (t.prependListener = m),
+              (t.prependOnceListener = m),
+              (t.listeners = function (e) {
+                return [];
+              }),
+              (t.binding = function (e) {
+                throw new Error('process.binding is not supported');
+              }),
+              (t.cwd = function () {
+                return '/';
+              }),
+              (t.chdir = function (e) {
+                throw new Error('process.chdir is not supported');
+              }),
+              (t.umask = function () {
+                return 0;
+              });
+          },
+          {}
+        ],
+        367: [
+          function (e, O, A) {
+            !function (S) {
+              !function () {
+                var e = this,
+                  t = 'object' == typeof A && A && !A.nodeType && A,
+                  r = 'object' == typeof O && O && !O.nodeType && O,
+                  n = 'object' == typeof S && S;
+                (n.global !== n && n.window !== n && n.self !== n) || (e = n);
+                var s,
+                  i,
+                  y = 2147483647,
+                  b = 36,
+                  g = 26,
+                  o = 38,
+                  a = 700,
+                  c = /^xn--/,
+                  l = /[^\x20-\x7E]/,
+                  u = /[\x2E\u3002\uFF0E\uFF61]/g,
+                  p = {
+                    overflow: 'Overflow: input needs wider integers to process',
+                    'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+                    'invalid-input': 'Invalid input'
+                  },
+                  f = b - 1,
+                  v = Math.floor,
+                  j = String.fromCharCode;
+                function w(e) {
+                  throw new RangeError(p[e]);
+                }
+                function d(e, t) {
+                  for (var r = e.length, n = []; r--; ) n[r] = t(e[r]);
+                  return n;
+                }
+                function h(e, t) {
+                  var r = e.split('@'),
+                    n = '',
+                    r = (1 < r.length && ((n = r[0] + '@'), (e = r[1])), (e = e.replace(u, '.')).split('.'));
+                  return n + d(r, t).join('.');
+                }
+                function x(e) {
+                  for (var t, r, n = [], s = 0, i = e.length; s < i; )
+                    55296 <= (t = e.charCodeAt(s++)) && t <= 56319 && s < i
+                      ? 56320 == (64512 & (r = e.charCodeAt(s++)))
+                        ? n.push(((1023 & t) << 10) + (1023 & r) + 65536)
+                        : (n.push(t), s--)
+                      : n.push(t);
+                  return n;
+                }
+                function m(e) {
+                  return d(e, function (e) {
+                    var t = '';
+                    return (
+                      65535 < e && ((t += j((((e -= 65536) >>> 10) & 1023) | 55296)), (e = 56320 | (1023 & e))),
+                      (t += j(e))
+                    );
+                  }).join('');
+                }
+                function T(e, t) {
+                  return e + 22 + 75 * (e < 26) - ((0 != t) << 5);
+                }
+                function k(e, t, r) {
+                  var n = 0;
+                  for (e = r ? v(e / a) : e >> 1, e += v(e / t); (f * g) >> 1 < e; n += b) e = v(e / f);
+                  return v(n + ((f + 1) * e) / (e + o));
+                }
+                function E(e) {
+                  var t,
+                    r,
+                    n,
+                    s,
+                    i,
+                    o,
+                    a,
+                    c = [],
+                    l = e.length,
+                    u = 0,
+                    p = 128,
+                    f = 72,
+                    d = e.lastIndexOf('-');
+                  for (d < 0 && (d = 0), r = 0; r < d; ++r)
+                    128 <= e.charCodeAt(r) && w('not-basic'), c.push(e.charCodeAt(r));
+                  for (n = 0 < d ? d + 1 : 0; n < l; ) {
+                    for (
+                      s = u, i = 1, o = b;
+                      l <= n && w('invalid-input'),
+                        (a = e.charCodeAt(n++)),
+                        (b <= (a = a - 48 < 10 ? a - 22 : a - 65 < 26 ? a - 65 : a - 97 < 26 ? a - 97 : b) ||
+                          a > v((y - u) / i)) &&
+                          w('overflow'),
+                        (u += a * i),
+                        !(a < (a = o <= f ? 1 : f + g <= o ? g : o - f));
+                      o += b
+                    )
+                      i > v(y / (a = b - a)) && w('overflow'), (i *= a);
+                    (f = k(u - s, (t = c.length + 1), 0 == s)),
+                      v(u / t) > y - p && w('overflow'),
+                      (p += v(u / t)),
+                      (u %= t),
+                      c.splice(u++, 0, p);
+                  }
+                  return m(c);
+                }
+                function _(e) {
+                  for (
+                    var t, r, n, s, i, o, a, c, l, u, p = [], f = (e = x(e)).length, d = 128, h = 72, m = (t = 0);
+                    m < f;
+                    ++m
+                  )
+                    (a = e[m]) < 128 && p.push(j(a));
+                  for (r = n = p.length, n && p.push('-'); r < f; ) {
+                    for (s = y, m = 0; m < f; ++m) d <= (a = e[m]) && a < s && (s = a);
+                    for (s - d > v((y - t) / (c = r + 1)) && w('overflow'), t += (s - d) * c, d = s, m = 0; m < f; ++m)
+                      if (((a = e[m]) < d && ++t > y && w('overflow'), a == d)) {
+                        for (i = t, o = b; !(i < (l = o <= h ? 1 : h + g <= o ? g : o - h)); o += b)
+                          p.push(j(T(l + ((u = i - l) % (l = b - l)), 0))), (i = v(u / l));
+                        p.push(j(T(i, 0))), (h = k(t, c, r == n)), (t = 0), ++r;
+                      }
+                    ++t, ++d;
+                  }
+                  return p.join('');
+                }
+                if (
+                  ((s = {
+                    version: '1.4.1',
+                    ucs2: { decode: x, encode: m },
+                    decode: E,
+                    encode: _,
+                    toASCII: function (e) {
+                      return h(e, function (e) {
+                        return l.test(e) ? 'xn--' + _(e) : e;
+                      });
+                    },
+                    toUnicode: function (e) {
+                      return h(e, function (e) {
+                        return c.test(e) ? E(e.slice(4).toLowerCase()) : e;
+                      });
+                    }
+                  }),
+                  t && r)
+                )
+                  if (O.exports == t) r.exports = s;
+                  else for (i in s) s.hasOwnProperty(i) && (t[i] = s[i]);
+                else e.punycode = s;
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        368: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = function (e, t, r, n) {
+              r = r || '=';
+              var s = {};
+              if ('string' != typeof e || 0 === e.length) return s;
+              var i = /\+/g,
+                t = ((e = e.split((t = t || '&'))), 1e3),
+                o = (n && 'number' == typeof n.maxKeys && (t = n.maxKeys), e.length);
+              0 < t && t < o && (o = t);
+              for (var a = 0; a < o; ++a) {
+                var c,
+                  l = e[a].replace(i, '%20'),
+                  u = l.indexOf(r),
+                  u = 0 <= u ? ((c = l.substr(0, u)), l.substr(u + 1)) : ((c = l), ''),
+                  l = decodeURIComponent(c),
+                  u = decodeURIComponent(u);
+                Object.prototype.hasOwnProperty.call(s, l) ? (p(s[l]) ? s[l].push(u) : (s[l] = [s[l], u])) : (s[l] = u);
+              }
+              return s;
+            };
+            var p =
+              Array.isArray ||
+              function (e) {
+                return '[object Array]' === Object.prototype.toString.call(e);
+              };
+          },
+          {}
+        ],
+        369: [
+          function (e, t, r) {
+            'use strict';
+            function i(e) {
+              switch (typeof e) {
+                case 'string':
+                  return e;
+                case 'boolean':
+                  return e ? 'true' : 'false';
+                case 'number':
+                  return isFinite(e) ? e : '';
+                default:
+                  return '';
+              }
+            }
+            t.exports = function (r, n, s, e) {
+              return (
+                (n = n || '&'),
+                (s = s || '='),
+                'object' == typeof (r = null === r ? void 0 : r)
+                  ? a(c(r), function (e) {
+                      var t = encodeURIComponent(i(e)) + s;
+                      return o(r[e])
+                        ? a(r[e], function (e) {
+                            return t + encodeURIComponent(i(e));
+                          }).join(n)
+                        : t + encodeURIComponent(i(r[e]));
+                    }).join(n)
+                  : e
+                  ? encodeURIComponent(i(e)) + s + encodeURIComponent(i(r))
+                  : ''
+              );
+            };
+            var o =
+              Array.isArray ||
+              function (e) {
+                return '[object Array]' === Object.prototype.toString.call(e);
+              };
+            function a(e, t) {
+              if (e.map) return e.map(t);
+              for (var r = [], n = 0; n < e.length; n++) r.push(t(e[n], n));
+              return r;
+            }
+            var c =
+              Object.keys ||
+              function (e) {
+                var t,
+                  r = [];
+                for (t in e) Object.prototype.hasOwnProperty.call(e, t) && r.push(t);
+                return r;
+              };
+          },
+          {}
+        ],
+        370: [
+          function (e, t, r) {
+            'use strict';
+            (r.decode = r.parse = e('./decode')), (r.encode = r.stringify = e('./encode'));
+          },
+          { './decode': 368, './encode': 369 }
+        ],
+        371: [
+          function (e, t, r) {
+            t.exports = e('./lib/_stream_duplex.js');
+          },
+          { './lib/_stream_duplex.js': 372 }
+        ],
+        372: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('process-nextick-args'),
+              s =
+                Object.keys ||
+                function (e) {
+                  var t,
+                    r = [];
+                  for (t in e) r.push(t);
+                  return r;
+                },
+              t = ((t.exports = u), Object.create(e('core-util-is'))),
+              i = ((t.inherits = e('inherits')), e('./_stream_readable')),
+              o = e('./_stream_writable');
+            t.inherits(u, i);
+            for (var a = s(o.prototype), c = 0; c < a.length; c++) {
+              var l = a[c];
+              u.prototype[l] || (u.prototype[l] = o.prototype[l]);
+            }
+            function u(e) {
+              if (!(this instanceof u)) return new u(e);
+              i.call(this, e),
+                o.call(this, e),
+                e && !1 === e.readable && (this.readable = !1),
+                e && !1 === e.writable && (this.writable = !1),
+                (this.allowHalfOpen = !0),
+                e && !1 === e.allowHalfOpen && (this.allowHalfOpen = !1),
+                this.once('end', p);
+            }
+            function p() {
+              this.allowHalfOpen || this._writableState.ended || n.nextTick(f, this);
+            }
+            function f(e) {
+              e.end();
+            }
+            Object.defineProperty(u.prototype, 'writableHighWaterMark', {
+              enumerable: !1,
+              get: function () {
+                return this._writableState.highWaterMark;
+              }
+            }),
+              Object.defineProperty(u.prototype, 'destroyed', {
+                get: function () {
+                  return (
+                    void 0 !== this._readableState &&
+                    void 0 !== this._writableState &&
+                    this._readableState.destroyed &&
+                    this._writableState.destroyed
+                  );
+                },
+                set: function (e) {
+                  void 0 !== this._readableState &&
+                    void 0 !== this._writableState &&
+                    ((this._readableState.destroyed = e), (this._writableState.destroyed = e));
+                }
+              }),
+              (u.prototype._destroy = function (e, t) {
+                this.push(null), this.end(), n.nextTick(t, e);
+              });
+          },
+          {
+            './_stream_readable': 374,
+            './_stream_writable': 376,
+            'core-util-is': 340,
+            inherits: 353,
+            'process-nextick-args': 365
+          }
+        ],
+        373: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = s;
+            var n = e('./_stream_transform'),
+              t = Object.create(e('core-util-is'));
+            function s(e) {
+              if (!(this instanceof s)) return new s(e);
+              n.call(this, e);
+            }
+            (t.inherits = e('inherits')),
+              t.inherits(s, n),
+              (s.prototype._transform = function (e, t, r) {
+                r(null, e);
+              });
+          },
+          { './_stream_transform': 375, 'core-util-is': 340, inherits: 353 }
+        ],
+        374: [
+          function (C, N, e) {
+            !function (D, I) {
+              !function () {
+                'use strict';
+                function m(e, t) {
+                  return e.listeners(t).length;
+                }
+                var i,
+                  y = C('process-nextick-args'),
+                  b = ((N.exports = s), C('isarray')),
+                  r = ((s.ReadableState = n), C('events').EventEmitter, C('./internal/streams/stream')),
+                  u = C('safe-buffer').Buffer,
+                  p = I.Uint8Array || function () {};
+                var o,
+                  e = Object.create(C('core-util-is')),
+                  t = ((e.inherits = C('inherits')), C('util')),
+                  g = void 0,
+                  g = t && t.debuglog ? t.debuglog('stream') : function () {},
+                  a = C('./internal/streams/BufferList'),
+                  t = C('./internal/streams/destroy'),
+                  c = (e.inherits(s, r), ['error', 'close', 'destroy', 'pause', 'resume']);
+                function n(e, t) {
+                  var t = t instanceof (i = i || C('./_stream_duplex')),
+                    r =
+                      ((this.objectMode = !!(e = e || {}).objectMode),
+                      t && (this.objectMode = this.objectMode || !!e.readableObjectMode),
+                      e.highWaterMark),
+                    n = e.readableHighWaterMark,
+                    s = this.objectMode ? 16 : 16384;
+                  (this.highWaterMark = r || 0 === r ? r : t && (n || 0 === n) ? n : s),
+                    (this.highWaterMark = Math.floor(this.highWaterMark)),
+                    (this.buffer = new a()),
+                    (this.length = 0),
+                    (this.pipes = null),
+                    (this.pipesCount = 0),
+                    (this.flowing = null),
+                    (this.ended = !1),
+                    (this.endEmitted = !1),
+                    (this.reading = !1),
+                    (this.sync = !0),
+                    (this.needReadable = !1),
+                    (this.emittedReadable = !1),
+                    (this.readableListening = !1),
+                    (this.resumeScheduled = !1),
+                    (this.destroyed = !1),
+                    (this.defaultEncoding = e.defaultEncoding || 'utf8'),
+                    (this.awaitDrain = 0),
+                    (this.readingMore = !1),
+                    (this.decoder = null),
+                    (this.encoding = null),
+                    e.encoding &&
+                      ((o = o || C('string_decoder/').StringDecoder),
+                      (this.decoder = new o(e.encoding)),
+                      (this.encoding = e.encoding));
+                }
+                function s(e) {
+                  if (((i = i || C('./_stream_duplex')), !(this instanceof s))) return new s(e);
+                  (this._readableState = new n(e, this)),
+                    (this.readable = !0),
+                    e &&
+                      ('function' == typeof e.read && (this._read = e.read),
+                      'function' == typeof e.destroy && (this._destroy = e.destroy)),
+                    r.call(this);
+                }
+                function l(e, t, r, n, s) {
+                  var i,
+                    o,
+                    a,
+                    c,
+                    l = e._readableState;
+                  return (
+                    null === t
+                      ? ((l.reading = !1),
+                        (o = e),
+                        (c = l).ended ||
+                          (c.decoder &&
+                            (a = c.decoder.end()) &&
+                            a.length &&
+                            (c.buffer.push(a), (c.length += c.objectMode ? 1 : a.length)),
+                          (c.ended = !0),
+                          v(o)))
+                      : (i = s
+                          ? i
+                          : (function (e, t) {
+                              var r;
+                              !(function (e) {
+                                return u.isBuffer(e) || e instanceof p;
+                              })(t) &&
+                                'string' != typeof t &&
+                                void 0 !== t &&
+                                !e.objectMode &&
+                                (r = new TypeError('Invalid non-string/buffer chunk'));
+                              return r;
+                            })(l, t))
+                      ? e.emit('error', i)
+                      : l.objectMode || (t && 0 < t.length)
+                      ? ('string' == typeof t ||
+                          l.objectMode ||
+                          Object.getPrototypeOf(t) === u.prototype ||
+                          ((a = t), (t = u.from(a))),
+                        n
+                          ? l.endEmitted
+                            ? e.emit('error', new Error('stream.unshift() after end event'))
+                            : f(e, l, t, !0)
+                          : l.ended
+                          ? e.emit('error', new Error('stream.push() after EOF'))
+                          : ((l.reading = !1),
+                            l.decoder && !r
+                              ? ((t = l.decoder.write(t)), l.objectMode || 0 !== t.length ? f(e, l, t, !1) : w(e, l))
+                              : f(e, l, t, !1)))
+                      : n || (l.reading = !1),
+                    !(c = l).ended && (c.needReadable || c.length < c.highWaterMark || 0 === c.length)
+                  );
+                }
+                function f(e, t, r, n) {
+                  t.flowing && 0 === t.length && !t.sync
+                    ? (e.emit('data', r), e.read(0))
+                    : ((t.length += t.objectMode ? 1 : r.length),
+                      n ? t.buffer.unshift(r) : t.buffer.push(r),
+                      t.needReadable && v(e)),
+                    w(e, t);
+                }
+                Object.defineProperty(s.prototype, 'destroyed', {
+                  get: function () {
+                    return void 0 !== this._readableState && this._readableState.destroyed;
+                  },
+                  set: function (e) {
+                    this._readableState && (this._readableState.destroyed = e);
+                  }
+                }),
+                  (s.prototype.destroy = t.destroy),
+                  (s.prototype._undestroy = t.undestroy),
+                  (s.prototype._destroy = function (e, t) {
+                    this.push(null), t(e);
+                  }),
+                  (s.prototype.push = function (e, t) {
+                    var r,
+                      n = this._readableState;
+                    return (
+                      n.objectMode
+                        ? (r = !0)
+                        : 'string' == typeof e &&
+                          ((t = t || n.defaultEncoding) !== n.encoding && ((e = u.from(e, t)), (t = '')), (r = !0)),
+                      l(this, e, t, !1, r)
+                    );
+                  }),
+                  (s.prototype.unshift = function (e) {
+                    return l(this, e, null, !0, !1);
+                  }),
+                  (s.prototype.isPaused = function () {
+                    return !1 === this._readableState.flowing;
+                  }),
+                  (s.prototype.setEncoding = function (e) {
+                    return (
+                      (o = o || C('string_decoder/').StringDecoder),
+                      (this._readableState.decoder = new o(e)),
+                      (this._readableState.encoding = e),
+                      this
+                    );
+                  });
+                var d = 8388608;
+                function h(e, t) {
+                  return e <= 0 || (0 === t.length && t.ended)
+                    ? 0
+                    : t.objectMode
+                    ? 1
+                    : e != e
+                    ? (t.flowing && t.length ? t.buffer.head.data : t).length
+                    : (e > t.highWaterMark &&
+                        (t.highWaterMark =
+                          (d <= (r = e)
+                            ? (r = d)
+                            : (r--,
+                              (r = (r = (r = (r = (r |= r >>> 1) | (r >>> 2)) | (r >>> 4)) | (r >>> 8)) | (r >>> 16)),
+                              r++),
+                          r)),
+                      e <= t.length ? e : t.ended ? t.length : ((t.needReadable = !0), 0));
+                  var r;
+                }
+                function v(e) {
+                  var t = e._readableState;
+                  (t.needReadable = !1),
+                    t.emittedReadable ||
+                      (g('emitReadable', t.flowing), (t.emittedReadable = !0), t.sync ? y.nextTick(j, e) : j(e));
+                }
+                function j(e) {
+                  g('emit readable'), e.emit('readable'), E(e);
+                }
+                function w(e, t) {
+                  t.readingMore || ((t.readingMore = !0), y.nextTick(x, e, t));
+                }
+                function x(e, t) {
+                  for (
+                    var r = t.length;
+                    !t.reading &&
+                    !t.flowing &&
+                    !t.ended &&
+                    t.length < t.highWaterMark &&
+                    (g('maybeReadMore read 0'), e.read(0), r !== t.length);
+
+                  )
+                    r = t.length;
+                  t.readingMore = !1;
+                }
+                function T(e) {
+                  g('readable nexttick read 0'), e.read(0);
+                }
+                function k(e, t) {
+                  t.reading || (g('resume read 0'), e.read(0)),
+                    (t.resumeScheduled = !1),
+                    (t.awaitDrain = 0),
+                    e.emit('resume'),
+                    E(e),
+                    t.flowing && !t.reading && e.read(0);
+                }
+                function E(e) {
+                  var t = e._readableState;
+                  for (g('flow', t.flowing); t.flowing && null !== e.read(); );
+                }
+                function _(e, t) {
+                  return 0 === t.length
+                    ? null
+                    : (t.objectMode
+                        ? (r = t.buffer.shift())
+                        : !e || e >= t.length
+                        ? ((r = t.decoder
+                            ? t.buffer.join('')
+                            : 1 === t.buffer.length
+                            ? t.buffer.head.data
+                            : t.buffer.concat(t.length)),
+                          t.buffer.clear())
+                        : (r = (function (e, t, r) {
+                            var n;
+                            e < t.head.data.length
+                              ? ((n = t.head.data.slice(0, e)), (t.head.data = t.head.data.slice(e)))
+                              : (n =
+                                  e === t.head.data.length
+                                    ? t.shift()
+                                    : (r
+                                        ? function (e, t) {
+                                            var r = t.head,
+                                              n = 1,
+                                              s = r.data;
+                                            e -= s.length;
+                                            for (; (r = r.next); ) {
+                                              var i = r.data,
+                                                o = e > i.length ? i.length : e;
+                                              if ((o === i.length ? (s += i) : (s += i.slice(0, e)), 0 === (e -= o))) {
+                                                o === i.length
+                                                  ? (++n, r.next ? (t.head = r.next) : (t.head = t.tail = null))
+                                                  : ((t.head = r).data = i.slice(o));
+                                                break;
+                                              }
+                                              ++n;
+                                            }
+                                            return (t.length -= n), s;
+                                          }
+                                        : function (e, t) {
+                                            var r = u.allocUnsafe(e),
+                                              n = t.head,
+                                              s = 1;
+                                            n.data.copy(r), (e -= n.data.length);
+                                            for (; (n = n.next); ) {
+                                              var i = n.data,
+                                                o = e > i.length ? i.length : e;
+                                              if ((i.copy(r, r.length - e, 0, o), 0 === (e -= o))) {
+                                                o === i.length
+                                                  ? (++s, n.next ? (t.head = n.next) : (t.head = t.tail = null))
+                                                  : ((t.head = n).data = i.slice(o));
+                                                break;
+                                              }
+                                              ++s;
+                                            }
+                                            return (t.length -= s), r;
+                                          })(e, t));
+                            return n;
+                          })(e, t.buffer, t.decoder)),
+                      r);
+                  var r;
+                }
+                function S(e) {
+                  var t = e._readableState;
+                  if (0 < t.length) throw new Error('"endReadable()" called on non-empty stream');
+                  t.endEmitted || ((t.ended = !0), y.nextTick(O, t, e));
+                }
+                function O(e, t) {
+                  e.endEmitted || 0 !== e.length || ((e.endEmitted = !0), (t.readable = !1), t.emit('end'));
+                }
+                function A(e, t) {
+                  for (var r = 0, n = e.length; r < n; r++) if (e[r] === t) return r;
+                  return -1;
+                }
+                (s.prototype.read = function (e) {
+                  g('read', e), (e = parseInt(e, 10));
+                  var t = this._readableState,
+                    r = e;
+                  if (
+                    (0 !== e && (t.emittedReadable = !1),
+                    0 === e && t.needReadable && (t.length >= t.highWaterMark || t.ended))
+                  )
+                    return g('read: emitReadable', t.length, t.ended), (0 === t.length && t.ended ? S : v)(this), null;
+                  if (0 === (e = h(e, t)) && t.ended) return 0 === t.length && S(this), null;
+                  var n = t.needReadable;
+                  return (
+                    g('need readable', n),
+                    (0 === t.length || t.length - e < t.highWaterMark) && g('length less than watermark', (n = !0)),
+                    t.ended || t.reading
+                      ? g('reading or ended', (n = !1))
+                      : n &&
+                        (g('do read'),
+                        (t.reading = !0),
+                        (t.sync = !0),
+                        0 === t.length && (t.needReadable = !0),
+                        this._read(t.highWaterMark),
+                        (t.sync = !1),
+                        t.reading || (e = h(r, t))),
+                    null === (n = 0 < e ? _(e, t) : null) ? ((t.needReadable = !0), (e = 0)) : (t.length -= e),
+                    0 === t.length && (t.ended || (t.needReadable = !0), r !== e && t.ended && S(this)),
+                    null !== n && this.emit('data', n),
+                    n
+                  );
+                }),
+                  (s.prototype._read = function (e) {
+                    this.emit('error', new Error('_read() is not implemented'));
+                  }),
+                  (s.prototype.pipe = function (r, e) {
+                    var n = this,
+                      s = this._readableState;
+                    switch (s.pipesCount) {
+                      case 0:
+                        s.pipes = r;
+                        break;
+                      case 1:
+                        s.pipes = [s.pipes, r];
+                        break;
+                      default:
+                        s.pipes.push(r);
+                    }
+                    (s.pipesCount += 1), g('pipe count=%d opts=%j', s.pipesCount, e);
+                    e = (!e || !1 !== e.end) && r !== D.stdout && r !== D.stderr ? o : h;
+                    function i(e, t) {
+                      g('onunpipe'),
+                        e === n &&
+                          t &&
+                          !1 === t.hasUnpiped &&
+                          ((t.hasUnpiped = !0),
+                          g('cleanup'),
+                          r.removeListener('close', f),
+                          r.removeListener('finish', d),
+                          r.removeListener('drain', a),
+                          r.removeListener('error', p),
+                          r.removeListener('unpipe', i),
+                          n.removeListener('end', o),
+                          n.removeListener('end', h),
+                          n.removeListener('data', u),
+                          (c = !0),
+                          !s.awaitDrain || (r._writableState && !r._writableState.needDrain) || a());
+                    }
+                    function o() {
+                      g('onend'), r.end();
+                    }
+                    s.endEmitted ? y.nextTick(e) : n.once('end', e), r.on('unpipe', i);
+                    t = n;
+                    var t,
+                      a = function () {
+                        var e = t._readableState;
+                        g('pipeOnDrain', e.awaitDrain),
+                          e.awaitDrain && e.awaitDrain--,
+                          0 === e.awaitDrain && m(t, 'data') && ((e.flowing = !0), E(t));
+                      },
+                      c = (r.on('drain', a), !1);
+                    var l = !1;
+                    function u(e) {
+                      g('ondata'),
+                        (l = !1) !== r.write(e) ||
+                          l ||
+                          (((1 === s.pipesCount && s.pipes === r) || (1 < s.pipesCount && -1 !== A(s.pipes, r))) &&
+                            !c &&
+                            (g('false write response, pause', n._readableState.awaitDrain),
+                            n._readableState.awaitDrain++,
+                            (l = !0)),
+                          n.pause());
+                    }
+                    function p(e) {
+                      g('onerror', e), h(), r.removeListener('error', p), 0 === m(r, 'error') && r.emit('error', e);
+                    }
+                    function f() {
+                      r.removeListener('finish', d), h();
+                    }
+                    function d() {
+                      g('onfinish'), r.removeListener('close', f), h();
+                    }
+                    function h() {
+                      g('unpipe'), n.unpipe(r);
+                    }
+                    return (
+                      n.on('data', u),
+                      (function (e, t, r) {
+                        if ('function' == typeof e.prependListener) return e.prependListener(t, r);
+                        e._events && e._events[t]
+                          ? b(e._events[t])
+                            ? e._events[t].unshift(r)
+                            : (e._events[t] = [r, e._events[t]])
+                          : e.on(t, r);
+                      })(r, 'error', p),
+                      r.once('close', f),
+                      r.once('finish', d),
+                      r.emit('pipe', n),
+                      s.flowing || (g('pipe resume'), n.resume()),
+                      r
+                    );
+                  }),
+                  (s.prototype.unpipe = function (e) {
+                    var t = this._readableState,
+                      r = { hasUnpiped: !1 };
+                    if (0 === t.pipesCount) return this;
+                    if (1 === t.pipesCount)
+                      return (
+                        (e && e !== t.pipes) ||
+                          ((e = e || t.pipes),
+                          (t.pipes = null),
+                          (t.pipesCount = 0),
+                          (t.flowing = !1),
+                          e && e.emit('unpipe', this, r)),
+                        this
+                      );
+                    if (!e) {
+                      var n = t.pipes,
+                        s = t.pipesCount;
+                      (t.pipes = null), (t.pipesCount = 0), (t.flowing = !1);
+                      for (var i = 0; i < s; i++) n[i].emit('unpipe', this, r);
+                      return this;
+                    }
+                    var o = A(t.pipes, e);
+                    return (
+                      -1 === o ||
+                        (t.pipes.splice(o, 1),
+                        --t.pipesCount,
+                        1 === t.pipesCount && (t.pipes = t.pipes[0]),
+                        e.emit('unpipe', this, r)),
+                      this
+                    );
+                  }),
+                  (s.prototype.addListener = s.prototype.on =
+                    function (e, t) {
+                      t = r.prototype.on.call(this, e, t);
+                      return (
+                        'data' === e
+                          ? !1 !== this._readableState.flowing && this.resume()
+                          : 'readable' !== e ||
+                            (e = this._readableState).endEmitted ||
+                            e.readableListening ||
+                            ((e.readableListening = e.needReadable = !0),
+                            (e.emittedReadable = !1),
+                            e.reading ? e.length && v(this) : y.nextTick(T, this)),
+                        t
+                      );
+                    }),
+                  (s.prototype.resume = function () {
+                    var e,
+                      t = this._readableState;
+                    return (
+                      t.flowing ||
+                        (g('resume'),
+                        (t.flowing = !0),
+                        (e = this),
+                        (t = t).resumeScheduled || ((t.resumeScheduled = !0), y.nextTick(k, e, t))),
+                      this
+                    );
+                  }),
+                  (s.prototype.pause = function () {
+                    return (
+                      g('call pause flowing=%j', this._readableState.flowing),
+                      !1 !== this._readableState.flowing &&
+                        (g('pause'), (this._readableState.flowing = !1), this.emit('pause')),
+                      this
+                    );
+                  }),
+                  (s.prototype.wrap = function (t) {
+                    var e,
+                      r = this,
+                      n = this._readableState,
+                      s = !1;
+                    for (e in (t.on('end', function () {
+                      var e;
+                      g('wrapped end'),
+                        n.decoder && !n.ended && (e = n.decoder.end()) && e.length && r.push(e),
+                        r.push(null);
+                    }),
+                    t.on('data', function (e) {
+                      g('wrapped data'),
+                        n.decoder && (e = n.decoder.write(e)),
+                        (n.objectMode && null == e) ||
+                          ((n.objectMode || (e && e.length)) && !r.push(e) && ((s = !0), t.pause()));
+                    }),
+                    t))
+                      void 0 === this[e] &&
+                        'function' == typeof t[e] &&
+                        (this[e] = (function (e) {
+                          return function () {
+                            return t[e].apply(t, arguments);
+                          };
+                        })(e));
+                    for (var i = 0; i < c.length; i++) t.on(c[i], this.emit.bind(this, c[i]));
+                    return (
+                      (this._read = function (e) {
+                        g('wrapped _read', e), s && ((s = !1), t.resume());
+                      }),
+                      this
+                    );
+                  }),
+                  Object.defineProperty(s.prototype, 'readableHighWaterMark', {
+                    enumerable: !1,
+                    get: function () {
+                      return this._readableState.highWaterMark;
+                    }
+                  }),
+                  (s._fromList = _);
+              }.call(this);
+            }.call(
+              this,
+              C('_process'),
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {
+            './_stream_duplex': 372,
+            './internal/streams/BufferList': 377,
+            './internal/streams/destroy': 378,
+            './internal/streams/stream': 379,
+            _process: 441,
+            'core-util-is': 340,
+            events: 343,
+            inherits: 353,
+            isarray: 355,
+            'process-nextick-args': 365,
+            'safe-buffer': 385,
+            'string_decoder/': 388,
+            util: 87
+          }
+        ],
+        375: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = s;
+            var n = e('./_stream_duplex'),
+              t = Object.create(e('core-util-is'));
+            function s(e) {
+              if (!(this instanceof s)) return new s(e);
+              n.call(this, e),
+                (this._transformState = {
+                  afterTransform: function (e, t) {
+                    var r = this._transformState,
+                      n = ((r.transforming = !1), r.writecb);
+                    if (!n) return this.emit('error', new Error('write callback called multiple times'));
+                    (r.writechunk = null),
+                      (r.writecb = null) != t && this.push(t),
+                      n(e),
+                      ((r = this._readableState).reading = !1),
+                      (r.needReadable || r.length < r.highWaterMark) && this._read(r.highWaterMark);
+                  }.bind(this),
+                  needTransform: !1,
+                  transforming: !1,
+                  writecb: null,
+                  writechunk: null,
+                  writeencoding: null
+                }),
+                (this._readableState.needReadable = !0),
+                (this._readableState.sync = !1),
+                e &&
+                  ('function' == typeof e.transform && (this._transform = e.transform),
+                  'function' == typeof e.flush && (this._flush = e.flush)),
+                this.on('prefinish', i);
+            }
+            function i() {
+              var r = this;
+              'function' == typeof this._flush
+                ? this._flush(function (e, t) {
+                    o(r, e, t);
+                  })
+                : o(this, null, null);
+            }
+            function o(e, t, r) {
+              if (t) return e.emit('error', t);
+              if ((null != r && e.push(r), e._writableState.length))
+                throw new Error('Calling transform done when ws.length != 0');
+              if (e._transformState.transforming) throw new Error('Calling transform done when still transforming');
+              e.push(null);
+            }
+            (t.inherits = e('inherits')),
+              t.inherits(s, n),
+              (s.prototype.push = function (e, t) {
+                return (this._transformState.needTransform = !1), n.prototype.push.call(this, e, t);
+              }),
+              (s.prototype._transform = function (e, t, r) {
+                throw new Error('_transform() is not implemented');
+              }),
+              (s.prototype._write = function (e, t, r) {
+                var n = this._transformState;
+                (n.writecb = r),
+                  (n.writechunk = e),
+                  (n.writeencoding = t),
+                  n.transforming ||
+                    ((r = this._readableState),
+                    (n.needTransform || r.needReadable || r.length < r.highWaterMark) && this._read(r.highWaterMark));
+              }),
+              (s.prototype._read = function (e) {
+                var t = this._transformState;
+                null !== t.writechunk && t.writecb && !t.transforming
+                  ? ((t.transforming = !0), this._transform(t.writechunk, t.writeencoding, t.afterTransform))
+                  : (t.needTransform = !0);
+              }),
+              (s.prototype._destroy = function (e, t) {
+                var r = this;
+                n.prototype._destroy.call(this, e, function (e) {
+                  t(e), r.emit('close');
+                });
+              });
+          },
+          { './_stream_duplex': 372, 'core-util-is': 340, inherits: 353 }
+        ],
+        376: [
+          function (T, k, e) {
+            !function (l, u, x) {
+              !function () {
+                'use strict';
+                var d = T('process-nextick-args');
+                function p(i) {
+                  var o = this;
+                  (this.next = null),
+                    (this.entry = null),
+                    (this.finish = function () {
+                      var e = o,
+                        t = i,
+                        r = void 0,
+                        n = e.entry;
+                      for (e.entry = null; n; ) {
+                        var s = n.callback;
+                        t.pendingcb--, s(r), (n = n.next);
+                      }
+                      t.corkedRequestsFree ? (t.corkedRequestsFree.next = e) : (t.corkedRequestsFree = e);
+                    });
+                }
+                k.exports = a;
+                var i,
+                  f = !l.browser && -1 < ['v0.10', 'v0.9.'].indexOf(l.version.slice(0, 5)) ? x : d.nextTick,
+                  e = ((a.WritableState = o), Object.create(T('core-util-is'))),
+                  t = ((e.inherits = T('inherits')), { deprecate: T('util-deprecate') }),
+                  r = T('./internal/streams/stream'),
+                  h = T('safe-buffer').Buffer,
+                  m = u.Uint8Array || function () {};
+                var n,
+                  s = T('./internal/streams/destroy');
+                function y() {}
+                function o(e, u) {
+                  i = i || T('./_stream_duplex');
+                  var t = u instanceof i,
+                    r =
+                      ((this.objectMode = !!(e = e || {}).objectMode),
+                      t && (this.objectMode = this.objectMode || !!e.writableObjectMode),
+                      e.highWaterMark),
+                    n = e.writableHighWaterMark,
+                    s = this.objectMode ? 16 : 16384,
+                    r =
+                      ((this.highWaterMark = r || 0 === r ? r : t && (n || 0 === n) ? n : s),
+                      (this.highWaterMark = Math.floor(this.highWaterMark)),
+                      (this.finalCalled = !1),
+                      (this.needDrain = !1),
+                      (this.ending = !1),
+                      (this.ended = !1),
+                      (this.finished = !1),
+                      (this.destroyed = !1) === e.decodeStrings);
+                  (this.decodeStrings = !r),
+                    (this.defaultEncoding = e.defaultEncoding || 'utf8'),
+                    (this.length = 0),
+                    (this.writing = !1),
+                    (this.corked = 0),
+                    (this.sync = !0),
+                    (this.bufferProcessing = !1),
+                    (this.onwrite = function (e) {
+                      (e = e), (r = (t = u)._writableState), (n = r.sync), (s = r.writecb);
+                      var t,
+                        r,
+                        n,
+                        s,
+                        i = r;
+                      {
+                        var o, a, c, l;
+                        ((i.writing = !1), (i.writecb = null), (i.length -= i.writelen), (i.writelen = 0), e)
+                          ? ((i = t),
+                            (a = n),
+                            (c = e),
+                            (l = s),
+                            --(o = r).pendingcb,
+                            a
+                              ? (d.nextTick(l, c),
+                                d.nextTick(w, i, o),
+                                (i._writableState.errorEmitted = !0),
+                                i.emit('error', c))
+                              : (l(c), (i._writableState.errorEmitted = !0), i.emit('error', c), w(i, o)))
+                          : ((e = j(r)) || r.corked || r.bufferProcessing || !r.bufferedRequest || v(t, r),
+                            n ? f(g, t, r, e, s) : g(t, r, e, s));
+                      }
+                    }),
+                    (this.writecb = null),
+                    (this.writelen = 0),
+                    (this.bufferedRequest = null),
+                    (this.lastBufferedRequest = null),
+                    (this.pendingcb = 0),
+                    (this.prefinished = !1),
+                    (this.errorEmitted = !1),
+                    (this.bufferedRequestCount = 0),
+                    (this.corkedRequestsFree = new p(this));
+                }
+                e.inherits(a, r),
+                  (o.prototype.getBuffer = function () {
+                    for (var e = this.bufferedRequest, t = []; e; ) t.push(e), (e = e.next);
+                    return t;
+                  });
+                try {
+                  Object.defineProperty(o.prototype, 'buffer', {
+                    get: t.deprecate(
+                      function () {
+                        return this.getBuffer();
+                      },
+                      '_writableState.buffer is deprecated. Use _writableState.getBuffer instead.',
+                      'DEP0003'
+                    )
+                  });
+                } catch (e) {}
+                function a(e) {
+                  if (((i = i || T('./_stream_duplex')), !(n.call(a, this) || this instanceof i))) return new a(e);
+                  (this._writableState = new o(e, this)),
+                    (this.writable = !0),
+                    e &&
+                      ('function' == typeof e.write && (this._write = e.write),
+                      'function' == typeof e.writev && (this._writev = e.writev),
+                      'function' == typeof e.destroy && (this._destroy = e.destroy),
+                      'function' == typeof e.final && (this._final = e.final)),
+                    r.call(this);
+                }
+                function b(e, t, r, n, s, i, o) {
+                  (t.writelen = n),
+                    (t.writecb = o),
+                    (t.writing = !0),
+                    (t.sync = !0),
+                    r ? e._writev(s, t.onwrite) : e._write(s, i, t.onwrite),
+                    (t.sync = !1);
+                }
+                function g(e, t, r, n) {
+                  var s;
+                  r || ((r = e), 0 === (s = t).length && s.needDrain && ((s.needDrain = !1), r.emit('drain'))),
+                    t.pendingcb--,
+                    n(),
+                    w(e, t);
+                }
+                function v(e, t) {
+                  t.bufferProcessing = !0;
+                  var r = t.bufferedRequest;
+                  if (e._writev && r && r.next) {
+                    for (
+                      var n = t.bufferedRequestCount,
+                        s = new Array(n),
+                        n = t.corkedRequestsFree,
+                        i = ((n.entry = r), 0),
+                        o = !0;
+                      r;
+
+                    )
+                      (s[i] = r).isBuf || (o = !1), (r = r.next), (i += 1);
+                    (s.allBuffers = o),
+                      b(e, t, !0, t.length, s, '', n.finish),
+                      t.pendingcb++,
+                      (t.lastBufferedRequest = null),
+                      n.next ? ((t.corkedRequestsFree = n.next), (n.next = null)) : (t.corkedRequestsFree = new p(t)),
+                      (t.bufferedRequestCount = 0);
+                  } else {
+                    for (; r; ) {
+                      var a = r.chunk,
+                        c = r.encoding,
+                        l = r.callback;
+                      if (
+                        (b(e, t, !1, t.objectMode ? 1 : a.length, a, c, l),
+                        (r = r.next),
+                        t.bufferedRequestCount--,
+                        t.writing)
+                      )
+                        break;
+                    }
+                    null === r && (t.lastBufferedRequest = null);
+                  }
+                  (t.bufferedRequest = r), (t.bufferProcessing = !1);
+                }
+                function j(e) {
+                  return e.ending && 0 === e.length && null === e.bufferedRequest && !e.finished && !e.writing;
+                }
+                function c(t, r) {
+                  t._final(function (e) {
+                    r.pendingcb--, e && t.emit('error', e), (r.prefinished = !0), t.emit('prefinish'), w(t, r);
+                  });
+                }
+                function w(e, t) {
+                  var r,
+                    n,
+                    s = j(t);
+                  return (
+                    s &&
+                      ((r = e),
+                      (n = t).prefinished ||
+                        n.finalCalled ||
+                        ('function' == typeof r._final
+                          ? (n.pendingcb++, (n.finalCalled = !0), d.nextTick(c, r, n))
+                          : ((n.prefinished = !0), r.emit('prefinish'))),
+                      0 === t.pendingcb && ((t.finished = !0), e.emit('finish'))),
+                    s
+                  );
+                }
+                'function' == typeof Symbol &&
+                Symbol.hasInstance &&
+                'function' == typeof Function.prototype[Symbol.hasInstance]
+                  ? ((n = Function.prototype[Symbol.hasInstance]),
+                    Object.defineProperty(a, Symbol.hasInstance, {
+                      value: function (e) {
+                        return !!n.call(this, e) || (this === a && e && e._writableState instanceof o);
+                      }
+                    }))
+                  : (n = function (e) {
+                      return e instanceof this;
+                    }),
+                  (a.prototype.pipe = function () {
+                    this.emit('error', new Error('Cannot pipe, not readable'));
+                  }),
+                  (a.prototype.write = function (e, t, r) {
+                    var n,
+                      s,
+                      i,
+                      o,
+                      a,
+                      c,
+                      l,
+                      u = this._writableState,
+                      p = !1,
+                      f = !u.objectMode && ((f = e), h.isBuffer(f) || f instanceof m);
+                    return (
+                      f && !h.isBuffer(e) && ((a = e), (e = h.from(a))),
+                      'function' == typeof t && ((r = t), (t = null)),
+                      (t = f ? 'buffer' : t || u.defaultEncoding),
+                      'function' != typeof r && (r = y),
+                      u.ended
+                        ? ((a = this),
+                          (c = r),
+                          (l = new Error('write after end')),
+                          a.emit('error', l),
+                          d.nextTick(c, l))
+                        : (f ||
+                            ((c = this),
+                            (l = u),
+                            (s = r),
+                            (o = !(i = !0)),
+                            null === (n = e)
+                              ? (o = new TypeError('May not write null values to stream'))
+                              : 'string' == typeof n ||
+                                void 0 === n ||
+                                l.objectMode ||
+                                (o = new TypeError('Invalid non-string/buffer chunk')),
+                            o && (c.emit('error', o), d.nextTick(s, o), (i = !1)),
+                            i)) &&
+                          (u.pendingcb++,
+                          (p = (function (e, t, r, n, s, i) {
+                            r ||
+                              ((o = (function (e, t, r) {
+                                e.objectMode || !1 === e.decodeStrings || 'string' != typeof t || (t = h.from(t, r));
+                                return t;
+                              })(t, n, s)),
+                              n !== o && ((r = !0), (s = 'buffer'), (n = o)));
+                            var o = t.objectMode ? 1 : n.length,
+                              a = ((t.length += o), t.length < t.highWaterMark);
+                            a || (t.needDrain = !0);
+                            {
+                              var c;
+                              t.writing || t.corked
+                                ? ((c = t.lastBufferedRequest),
+                                  (t.lastBufferedRequest = {
+                                    chunk: n,
+                                    encoding: s,
+                                    isBuf: r,
+                                    callback: i,
+                                    next: null
+                                  }),
+                                  c ? (c.next = t.lastBufferedRequest) : (t.bufferedRequest = t.lastBufferedRequest),
+                                  (t.bufferedRequestCount += 1))
+                                : b(e, t, !1, o, n, s, i);
+                            }
+                            return a;
+                          })(this, u, f, e, t, r))),
+                      p
+                    );
+                  }),
+                  (a.prototype.cork = function () {
+                    this._writableState.corked++;
+                  }),
+                  (a.prototype.uncork = function () {
+                    var e = this._writableState;
+                    e.corked &&
+                      (e.corked--,
+                      e.writing || e.corked || e.finished || e.bufferProcessing || !e.bufferedRequest || v(this, e));
+                  }),
+                  (a.prototype.setDefaultEncoding = function (e) {
+                    if (
+                      ('string' == typeof e && (e = e.toLowerCase()),
+                      -1 <
+                        [
+                          'hex',
+                          'utf8',
+                          'utf-8',
+                          'ascii',
+                          'binary',
+                          'base64',
+                          'ucs2',
+                          'ucs-2',
+                          'utf16le',
+                          'utf-16le',
+                          'raw'
+                        ].indexOf((e + '').toLowerCase()))
+                    )
+                      return (this._writableState.defaultEncoding = e), this;
+                    throw new TypeError('Unknown encoding: ' + e);
+                  }),
+                  Object.defineProperty(a.prototype, 'writableHighWaterMark', {
+                    enumerable: !1,
+                    get: function () {
+                      return this._writableState.highWaterMark;
+                    }
+                  }),
+                  (a.prototype._write = function (e, t, r) {
+                    r(new Error('_write() is not implemented'));
+                  }),
+                  (a.prototype._writev = null),
+                  (a.prototype.end = function (e, t, r) {
+                    var n = this._writableState;
+                    if (
+                      ('function' == typeof e
+                        ? ((r = e), (t = e = null))
+                        : 'function' == typeof t && ((r = t), (t = null)),
+                      null != e && this.write(e, t),
+                      n.corked && ((n.corked = 1), this.uncork()),
+                      !n.ending && !n.finished)
+                    ) {
+                      (e = this), (t = n), (n = r);
+                      (t.ending = !0),
+                        w(e, t),
+                        n && (t.finished ? d.nextTick(n) : e.once('finish', n)),
+                        (t.ended = !0),
+                        (e.writable = !1);
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'destroyed', {
+                    get: function () {
+                      return void 0 !== this._writableState && this._writableState.destroyed;
+                    },
+                    set: function (e) {
+                      this._writableState && (this._writableState.destroyed = e);
+                    }
+                  }),
+                  (a.prototype.destroy = s.destroy),
+                  (a.prototype._undestroy = s.undestroy),
+                  (a.prototype._destroy = function (e, t) {
+                    this.end(), t(e);
+                  });
+              }.call(this);
+            }.call(
+              this,
+              T('_process'),
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {},
+              T('timers').setImmediate
+            );
+          },
+          {
+            './_stream_duplex': 372,
+            './internal/streams/destroy': 378,
+            './internal/streams/stream': 379,
+            _process: 441,
+            'core-util-is': 340,
+            inherits: 353,
+            'process-nextick-args': 365,
+            'safe-buffer': 385,
+            timers: 389,
+            'util-deprecate': 391
+          }
+        ],
+        377: [
+          function (e, t, r) {
+            'use strict';
+            var o = e('safe-buffer').Buffer,
+              n = e('util');
+            function s() {
+              if (!(this instanceof s)) throw new TypeError('Cannot call a class as a function');
+              (this.head = null), (this.tail = null), (this.length = 0);
+            }
+            (t.exports =
+              ((s.prototype.push = function (e) {
+                e = { data: e, next: null };
+                0 < this.length ? (this.tail.next = e) : (this.head = e), (this.tail = e), ++this.length;
+              }),
+              (s.prototype.unshift = function (e) {
+                e = { data: e, next: this.head };
+                0 === this.length && (this.tail = e), (this.head = e), ++this.length;
+              }),
+              (s.prototype.shift = function () {
+                var e;
+                if (0 !== this.length)
+                  return (
+                    (e = this.head.data),
+                    1 === this.length ? (this.head = this.tail = null) : (this.head = this.head.next),
+                    --this.length,
+                    e
+                  );
+              }),
+              (s.prototype.clear = function () {
+                (this.head = this.tail = null), (this.length = 0);
+              }),
+              (s.prototype.join = function (e) {
+                if (0 === this.length) return '';
+                for (var t = this.head, r = '' + t.data; (t = t.next); ) r += e + t.data;
+                return r;
+              }),
+              (s.prototype.concat = function (e) {
+                if (0 === this.length) return o.alloc(0);
+                if (1 === this.length) return this.head.data;
+                for (var t, r, n = o.allocUnsafe(e >>> 0), s = this.head, i = 0; s; )
+                  (t = s.data), (r = i), t.copy(n, r), (i += s.data.length), (s = s.next);
+                return n;
+              }),
+              s)),
+              n &&
+                n.inspect &&
+                n.inspect.custom &&
+                (t.exports.prototype[n.inspect.custom] = function () {
+                  var e = n.inspect({ length: this.length });
+                  return this.constructor.name + ' ' + e;
+                });
+          },
+          { 'safe-buffer': 385, util: 87 }
+        ],
+        378: [
+          function (e, t, r) {
+            'use strict';
+            var i = e('process-nextick-args');
+            function o(e, t) {
+              e.emit('error', t);
+            }
+            t.exports = {
+              destroy: function (e, t) {
+                var r = this,
+                  n = this._readableState && this._readableState.destroyed,
+                  s = this._writableState && this._writableState.destroyed;
+                return (
+                  n || s
+                    ? t
+                      ? t(e)
+                      : !e || (this._writableState && this._writableState.errorEmitted) || i.nextTick(o, this, e)
+                    : (this._readableState && (this._readableState.destroyed = !0),
+                      this._writableState && (this._writableState.destroyed = !0),
+                      this._destroy(e || null, function (e) {
+                        !t && e
+                          ? (i.nextTick(o, r, e), r._writableState && (r._writableState.errorEmitted = !0))
+                          : t && t(e);
+                      })),
+                  this
+                );
+              },
+              undestroy: function () {
+                this._readableState &&
+                  ((this._readableState.destroyed = !1),
+                  (this._readableState.reading = !1),
+                  (this._readableState.ended = !1),
+                  (this._readableState.endEmitted = !1)),
+                  this._writableState &&
+                    ((this._writableState.destroyed = !1),
+                    (this._writableState.ended = !1),
+                    (this._writableState.ending = !1),
+                    (this._writableState.finished = !1),
+                    (this._writableState.errorEmitted = !1));
+              }
+            };
+          },
+          { 'process-nextick-args': 365 }
+        ],
+        379: [
+          function (e, t, r) {
+            t.exports = e('events').EventEmitter;
+          },
+          { events: 343 }
+        ],
+        380: [
+          function (e, t, r) {
+            t.exports = e('./readable').PassThrough;
+          },
+          { './readable': 381 }
+        ],
+        381: [
+          function (e, t, r) {
+            ((((r = t.exports = e('./lib/_stream_readable.js')).Stream = r).Readable = r).Writable =
+              e('./lib/_stream_writable.js')),
+              (r.Duplex = e('./lib/_stream_duplex.js')),
+              (r.Transform = e('./lib/_stream_transform.js')),
+              (r.PassThrough = e('./lib/_stream_passthrough.js'));
+          },
+          {
+            './lib/_stream_duplex.js': 372,
+            './lib/_stream_passthrough.js': 373,
+            './lib/_stream_readable.js': 374,
+            './lib/_stream_transform.js': 375,
+            './lib/_stream_writable.js': 376
+          }
+        ],
+        382: [
+          function (e, t, r) {
+            t.exports = e('./readable').Transform;
+          },
+          { './readable': 381 }
+        ],
+        383: [
+          function (e, t, r) {
+            t.exports = e('./lib/_stream_writable.js');
+          },
+          { './lib/_stream_writable.js': 376 }
+        ],
+        384: [
+          function (e, t, r) {
+            t = (function (o) {
+              'use strict';
+              var c,
+                e = Object.prototype,
+                l = e.hasOwnProperty,
+                t = 'function' == typeof Symbol ? Symbol : {},
+                n = t.iterator || '@@iterator',
+                r = t.asyncIterator || '@@asyncIterator',
+                s = t.toStringTag || '@@toStringTag';
+              function i(e, t, r) {
+                return Object.defineProperty(e, t, { value: r, enumerable: !0, configurable: !0, writable: !0 }), e[t];
+              }
+              try {
+                i({}, '');
+              } catch (e) {
+                i = function (e, t, r) {
+                  return (e[t] = r);
+                };
+              }
+              function a(e, t, r, n) {
+                var s,
+                  i,
+                  o,
+                  a,
+                  t = t && t.prototype instanceof y ? t : y,
+                  t = Object.create(t.prototype),
+                  n = new E(n || []);
+                return (
+                  (t._invoke =
+                    ((s = e),
+                    (i = r),
+                    (o = n),
+                    (a = p),
+                    function (e, t) {
+                      if (a === d) throw new Error('Generator is already running');
+                      if (a === h) {
+                        if ('throw' === e) throw t;
+                        return S();
+                      }
+                      for (o.method = e, o.arg = t; ; ) {
+                        var r = o.delegate;
+                        if (r) {
+                          r = (function e(t, r) {
+                            var n = t.iterator[r.method];
+                            if (n === c) {
+                              if (((r.delegate = null), 'throw' === r.method)) {
+                                if (
+                                  t.iterator.return &&
+                                  ((r.method = 'return'), (r.arg = c), e(t, r), 'throw' === r.method)
+                                )
+                                  return m;
+                                (r.method = 'throw'),
+                                  (r.arg = new TypeError("The iterator does not provide a 'throw' method"));
+                              }
+                              return m;
+                            }
+                            n = u(n, t.iterator, r.arg);
+                            if ('throw' === n.type)
+                              return (r.method = 'throw'), (r.arg = n.arg), (r.delegate = null), m;
+                            n = n.arg;
+                            if (!n)
+                              return (
+                                (r.method = 'throw'),
+                                (r.arg = new TypeError('iterator result is not an object')),
+                                (r.delegate = null),
+                                m
+                              );
+                            {
+                              if (!n.done) return n;
+                              (r[t.resultName] = n.value),
+                                (r.next = t.nextLoc),
+                                'return' !== r.method && ((r.method = 'next'), (r.arg = c));
+                            }
+                            r.delegate = null;
+                            return m;
+                          })(r, o);
+                          if (r) {
+                            if (r === m) continue;
+                            return r;
+                          }
+                        }
+                        if ('next' === o.method) o.sent = o._sent = o.arg;
+                        else if ('throw' === o.method) {
+                          if (a === p) throw ((a = h), o.arg);
+                          o.dispatchException(o.arg);
+                        } else 'return' === o.method && o.abrupt('return', o.arg);
+                        a = d;
+                        r = u(s, i, o);
+                        if ('normal' === r.type) {
+                          if (((a = o.done ? h : f), r.arg !== m)) return { value: r.arg, done: o.done };
+                        } else 'throw' === r.type && ((a = h), (o.method = 'throw'), (o.arg = r.arg));
+                      }
+                    })),
+                  t
+                );
+              }
+              function u(e, t, r) {
+                try {
+                  return { type: 'normal', arg: e.call(t, r) };
+                } catch (e) {
+                  return { type: 'throw', arg: e };
+                }
+              }
+              o.wrap = a;
+              var p = 'suspendedStart',
+                f = 'suspendedYield',
+                d = 'executing',
+                h = 'completed',
+                m = {};
+              function y() {}
+              function b() {}
+              function g() {}
+              var t = {},
+                v =
+                  (i(t, n, function () {
+                    return this;
+                  }),
+                  Object.getPrototypeOf),
+                v = v && v(v(_([]))),
+                j = (v && v !== e && l.call(v, n) && (t = v), (g.prototype = y.prototype = Object.create(t)));
+              function w(e) {
+                ['next', 'throw', 'return'].forEach(function (t) {
+                  i(e, t, function (e) {
+                    return this._invoke(t, e);
+                  });
+                });
+              }
+              function x(o, a) {
+                var t;
+                this._invoke = function (r, n) {
+                  function e() {
+                    return new a(function (e, t) {
+                      !(function t(e, r, n, s) {
+                        var i,
+                          e = u(o[e], o, r);
+                        if ('throw' !== e.type)
+                          return (r = (i = e.arg).value) && 'object' == typeof r && l.call(r, '__await')
+                            ? a.resolve(r.__await).then(
+                                function (e) {
+                                  t('next', e, n, s);
+                                },
+                                function (e) {
+                                  t('throw', e, n, s);
+                                }
+                              )
+                            : a.resolve(r).then(
+                                function (e) {
+                                  (i.value = e), n(i);
+                                },
+                                function (e) {
+                                  return t('throw', e, n, s);
+                                }
+                              );
+                        s(e.arg);
+                      })(r, n, e, t);
+                    });
+                  }
+                  return (t = t ? t.then(e, e) : e());
+                };
+              }
+              function T(e) {
+                var t = { tryLoc: e[0] };
+                1 in e && (t.catchLoc = e[1]),
+                  2 in e && ((t.finallyLoc = e[2]), (t.afterLoc = e[3])),
+                  this.tryEntries.push(t);
+              }
+              function k(e) {
+                var t = e.completion || {};
+                (t.type = 'normal'), delete t.arg, (e.completion = t);
+              }
+              function E(e) {
+                (this.tryEntries = [{ tryLoc: 'root' }]), e.forEach(T, this), this.reset(!0);
+              }
+              function _(t) {
+                if (t) {
+                  var r,
+                    e = t[n];
+                  if (e) return e.call(t);
+                  if ('function' == typeof t.next) return t;
+                  if (!isNaN(t.length))
+                    return (
+                      (r = -1),
+                      ((e = function e() {
+                        for (; ++r < t.length; ) if (l.call(t, r)) return (e.value = t[r]), (e.done = !1), e;
+                        return (e.value = c), (e.done = !0), e;
+                      }).next = e)
+                    );
+                }
+                return { next: S };
+              }
+              function S() {
+                return { value: c, done: !0 };
+              }
+              return (
+                i(j, 'constructor', (b.prototype = g)),
+                i(g, 'constructor', b),
+                (b.displayName = i(g, s, 'GeneratorFunction')),
+                (o.isGeneratorFunction = function (e) {
+                  e = 'function' == typeof e && e.constructor;
+                  return !!e && (e === b || 'GeneratorFunction' === (e.displayName || e.name));
+                }),
+                (o.mark = function (e) {
+                  return (
+                    Object.setPrototypeOf
+                      ? Object.setPrototypeOf(e, g)
+                      : ((e.__proto__ = g), i(e, s, 'GeneratorFunction')),
+                    (e.prototype = Object.create(j)),
+                    e
+                  );
+                }),
+                (o.awrap = function (e) {
+                  return { __await: e };
+                }),
+                w(x.prototype),
+                i(x.prototype, r, function () {
+                  return this;
+                }),
+                (o.AsyncIterator = x),
+                (o.async = function (e, t, r, n, s) {
+                  void 0 === s && (s = Promise);
+                  var i = new x(a(e, t, r, n), s);
+                  return o.isGeneratorFunction(t)
+                    ? i
+                    : i.next().then(function (e) {
+                        return e.done ? e.value : i.next();
+                      });
+                }),
+                w(j),
+                i(j, s, 'Generator'),
+                i(j, n, function () {
+                  return this;
+                }),
+                i(j, 'toString', function () {
+                  return '[object Generator]';
+                }),
+                (o.keys = function (r) {
+                  var e,
+                    n = [];
+                  for (e in r) n.push(e);
+                  return (
+                    n.reverse(),
+                    function e() {
+                      for (; n.length; ) {
+                        var t = n.pop();
+                        if (t in r) return (e.value = t), (e.done = !1), e;
+                      }
+                      return (e.done = !0), e;
+                    }
+                  );
+                }),
+                (o.values = _),
+                (E.prototype = {
+                  constructor: E,
+                  reset: function (e) {
+                    if (
+                      ((this.prev = 0),
+                      (this.next = 0),
+                      (this.sent = this._sent = c),
+                      (this.done = !1),
+                      (this.delegate = null),
+                      (this.method = 'next'),
+                      (this.arg = c),
+                      this.tryEntries.forEach(k),
+                      !e)
+                    )
+                      for (var t in this)
+                        't' === t.charAt(0) && l.call(this, t) && !isNaN(+t.slice(1)) && (this[t] = c);
+                  },
+                  stop: function () {
+                    this.done = !0;
+                    var e = this.tryEntries[0].completion;
+                    if ('throw' === e.type) throw e.arg;
+                    return this.rval;
+                  },
+                  dispatchException: function (r) {
+                    if (this.done) throw r;
+                    var n = this;
+                    function e(e, t) {
+                      return (
+                        (i.type = 'throw'), (i.arg = r), (n.next = e), t && ((n.method = 'next'), (n.arg = c)), !!t
+                      );
+                    }
+                    for (var t = this.tryEntries.length - 1; 0 <= t; --t) {
+                      var s = this.tryEntries[t],
+                        i = s.completion;
+                      if ('root' === s.tryLoc) return e('end');
+                      if (s.tryLoc <= this.prev) {
+                        var o = l.call(s, 'catchLoc'),
+                          a = l.call(s, 'finallyLoc');
+                        if (o && a) {
+                          if (this.prev < s.catchLoc) return e(s.catchLoc, !0);
+                          if (this.prev < s.finallyLoc) return e(s.finallyLoc);
+                        } else if (o) {
+                          if (this.prev < s.catchLoc) return e(s.catchLoc, !0);
+                        } else {
+                          if (!a) throw new Error('try statement without catch or finally');
+                          if (this.prev < s.finallyLoc) return e(s.finallyLoc);
+                        }
+                      }
+                    }
+                  },
+                  abrupt: function (e, t) {
+                    for (var r = this.tryEntries.length - 1; 0 <= r; --r) {
+                      var n = this.tryEntries[r];
+                      if (n.tryLoc <= this.prev && l.call(n, 'finallyLoc') && this.prev < n.finallyLoc) {
+                        var s = n;
+                        break;
+                      }
+                    }
+                    var i = (s =
+                      s && ('break' === e || 'continue' === e) && s.tryLoc <= t && t <= s.finallyLoc ? null : s)
+                      ? s.completion
+                      : {};
+                    return (
+                      (i.type = e),
+                      (i.arg = t),
+                      s ? ((this.method = 'next'), (this.next = s.finallyLoc), m) : this.complete(i)
+                    );
+                  },
+                  complete: function (e, t) {
+                    if ('throw' === e.type) throw e.arg;
+                    return (
+                      'break' === e.type || 'continue' === e.type
+                        ? (this.next = e.arg)
+                        : 'return' === e.type
+                        ? ((this.rval = this.arg = e.arg), (this.method = 'return'), (this.next = 'end'))
+                        : 'normal' === e.type && t && (this.next = t),
+                      m
+                    );
+                  },
+                  finish: function (e) {
+                    for (var t = this.tryEntries.length - 1; 0 <= t; --t) {
+                      var r = this.tryEntries[t];
+                      if (r.finallyLoc === e) return this.complete(r.completion, r.afterLoc), k(r), m;
+                    }
+                  },
+                  catch: function (e) {
+                    for (var t = this.tryEntries.length - 1; 0 <= t; --t) {
+                      var r,
+                        n,
+                        s = this.tryEntries[t];
+                      if (s.tryLoc === e) return 'throw' === (r = s.completion).type && ((n = r.arg), k(s)), n;
+                    }
+                    throw new Error('illegal catch attempt');
+                  },
+                  delegateYield: function (e, t, r) {
+                    return (
+                      (this.delegate = { iterator: _(e), resultName: t, nextLoc: r }),
+                      'next' === this.method && (this.arg = c),
+                      m
+                    );
+                  }
+                }),
+                o
+              );
+            })('object' == typeof t ? t.exports : {});
+            try {
+              regeneratorRuntime = t;
+            } catch (e) {
+              'object' == typeof globalThis
+                ? (globalThis.regeneratorRuntime = t)
+                : Function('r', 'regeneratorRuntime = r')(t);
+            }
+          },
+          {}
+        ],
+        385: [
+          function (e, t, r) {
+            var n = e('buffer'),
+              s = n.Buffer;
+            function i(e, t) {
+              for (var r in e) t[r] = e[r];
+            }
+            function o(e, t, r) {
+              return s(e, t, r);
+            }
+            s.from && s.alloc && s.allocUnsafe && s.allocUnsafeSlow ? (t.exports = n) : (i(n, r), (r.Buffer = o)),
+              i(s, o),
+              (o.from = function (e, t, r) {
+                if ('number' == typeof e) throw new TypeError('Argument must not be a number');
+                return s(e, t, r);
+              }),
+              (o.alloc = function (e, t, r) {
+                if ('number' != typeof e) throw new TypeError('Argument must be a number');
+                e = s(e);
+                return void 0 !== t ? ('string' == typeof r ? e.fill(t, r) : e.fill(t)) : e.fill(0), e;
+              }),
+              (o.allocUnsafe = function (e) {
+                if ('number' != typeof e) throw new TypeError('Argument must be a number');
+                return s(e);
+              }),
+              (o.allocUnsafeSlow = function (e) {
+                if ('number' != typeof e) throw new TypeError('Argument must be a number');
+                return n.SlowBuffer(e);
+              });
+          },
+          { buffer: 89 }
+        ],
+        386: [
+          function (L, e, B) {
+            !function (r) {
+              !function () {
+                var a = void 0 === B ? (this.sax = {}) : B;
+                (a.parser = function (e, t) {
+                  return new o(e, t);
+                }),
+                  (a.SAXParser = o),
+                  (a.SAXStream = i),
+                  (a.createStream = function (e, t) {
+                    return new i(e, t);
+                  }),
+                  (a.MAX_BUFFER_LENGTH = 65536);
+                var n,
+                  c = [
+                    'comment',
+                    'sgmlDecl',
+                    'textNode',
+                    'tagName',
+                    'doctype',
+                    'procInstName',
+                    'procInstBody',
+                    'entity',
+                    'attribName',
+                    'attribValue',
+                    'cdata',
+                    'script'
+                  ];
+                function o(e, t) {
+                  if (!(this instanceof o)) return new o(e, t);
+                  for (var r = this, n = r, s = 0, i = c.length; s < i; s++) n[c[s]] = '';
+                  (r.q = r.c = ''),
+                    (r.bufferCheckPosition = a.MAX_BUFFER_LENGTH),
+                    (r.opt = t || {}),
+                    (r.opt.lowercase = r.opt.lowercase || r.opt.lowercasetags),
+                    (r.looseCase = r.opt.lowercase ? 'toLowerCase' : 'toUpperCase'),
+                    (r.tags = []),
+                    (r.closed = r.closedRoot = r.sawRoot = !1),
+                    (r.tag = r.error = null),
+                    (r.strict = !!e),
+                    (r.noscript = !(!e && !r.opt.noscript)),
+                    (r.state = T.BEGIN),
+                    (r.strictEntities = r.opt.strictEntities),
+                    (r.ENTITIES = r.strictEntities ? Object.create(a.XML_ENTITIES) : Object.create(a.ENTITIES)),
+                    (r.attribList = []),
+                    r.opt.xmlns && (r.ns = Object.create(d)),
+                    (r.trackPosition = !1 !== r.opt.position),
+                    r.trackPosition && (r.position = r.line = r.column = 0),
+                    k(r, 'onready');
+                }
+                (a.EVENTS = [
+                  'text',
+                  'processinginstruction',
+                  'sgmldeclaration',
+                  'doctype',
+                  'comment',
+                  'opentagstart',
+                  'attribute',
+                  'opentag',
+                  'closetag',
+                  'opencdata',
+                  'cdata',
+                  'closecdata',
+                  'error',
+                  'end',
+                  'ready',
+                  'script',
+                  'opennamespace',
+                  'closenamespace'
+                ]),
+                  Object.create ||
+                    (Object.create = function (e) {
+                      function t() {}
+                      return (t.prototype = e), new t();
+                    }),
+                  Object.keys ||
+                    (Object.keys = function (e) {
+                      var t,
+                        r = [];
+                      for (t in e) e.hasOwnProperty(t) && r.push(t);
+                      return r;
+                    }),
+                  (o.prototype = {
+                    end: function () {
+                      A(this);
+                    },
+                    write: function (e) {
+                      var t = this;
+                      if (this.error) throw this.error;
+                      if (t.closed) return O(t, 'Cannot write after close. Assign an onready handler.');
+                      if (null === e) return A(t);
+                      'object' == typeof e && (e = e.toString());
+                      var r,
+                        n,
+                        s = 0,
+                        i = '';
+                      for (;;) {
+                        if (((i = M(e, s++)), !(t.c = i))) break;
+                        switch (
+                          (t.trackPosition && (t.position++, '\n' === i ? (t.line++, (t.column = 0)) : t.column++),
+                          t.state)
+                        ) {
+                          case T.BEGIN:
+                            if (((t.state = T.BEGIN_WHITESPACE), '\ufeff' === i)) continue;
+                            P(t, i);
+                            continue;
+                          case T.BEGIN_WHITESPACE:
+                            P(t, i);
+                            continue;
+                          case T.TEXT:
+                            if (t.sawRoot && !t.closedRoot) {
+                              for (var o = s - 1; i && '<' !== i && '&' !== i; )
+                                (i = M(e, s++)) &&
+                                  t.trackPosition &&
+                                  (t.position++, '\n' === i ? (t.line++, (t.column = 0)) : t.column++);
+                              t.textNode += e.substring(o, s - 1);
+                            }
+                            '<' !== i || (t.sawRoot && t.closedRoot && !t.strict)
+                              ? (g(i) || (t.sawRoot && !t.closedRoot) || D(t, 'Text data outside of root node.'),
+                                '&' === i ? (t.state = T.TEXT_ENTITY) : (t.textNode += i))
+                              : ((t.state = T.OPEN_WAKA), (t.startTagPosition = t.position));
+                            continue;
+                          case T.SCRIPT:
+                            '<' === i ? (t.state = T.SCRIPT_ENDING) : (t.script += i);
+                            continue;
+                          case T.SCRIPT_ENDING:
+                            '/' === i ? (t.state = T.CLOSE_TAG) : ((t.script += '<' + i), (t.state = T.SCRIPT));
+                            continue;
+                          case T.OPEN_WAKA:
+                            '!' === i
+                              ? ((t.state = T.SGML_DECL), (t.sgmlDecl = ''))
+                              : g(i) ||
+                                (j(h, i)
+                                  ? ((t.state = T.OPEN_TAG), (t.tagName = i))
+                                  : '/' === i
+                                  ? ((t.state = T.CLOSE_TAG), (t.tagName = ''))
+                                  : '?' === i
+                                  ? ((t.state = T.PROC_INST), (t.procInstName = t.procInstBody = ''))
+                                  : (D(t, 'Unencoded <'),
+                                    t.startTagPosition + 1 < t.position &&
+                                      ((o = t.position - t.startTagPosition), (i = new Array(o).join(' ') + i)),
+                                    (t.textNode += '<' + i),
+                                    (t.state = T.TEXT)));
+                            continue;
+                          case T.SGML_DECL:
+                            (t.sgmlDecl + i).toUpperCase() === l
+                              ? (E(t, 'onopencdata'), (t.state = T.CDATA), (t.sgmlDecl = ''), (t.cdata = ''))
+                              : t.sgmlDecl + i === '--'
+                              ? ((t.state = T.COMMENT), (t.comment = ''), (t.sgmlDecl = ''))
+                              : (t.sgmlDecl + i).toUpperCase() === u
+                              ? ((t.state = T.DOCTYPE),
+                                (t.doctype || t.sawRoot) && D(t, 'Inappropriately located doctype declaration'),
+                                (t.doctype = ''),
+                                (t.sgmlDecl = ''))
+                              : '>' === i
+                              ? (E(t, 'onsgmldeclaration', t.sgmlDecl), (t.sgmlDecl = ''), (t.state = T.TEXT))
+                              : (v(i) && (t.state = T.SGML_DECL_QUOTED), (t.sgmlDecl += i));
+                            continue;
+                          case T.SGML_DECL_QUOTED:
+                            i === t.q && ((t.state = T.SGML_DECL), (t.q = '')), (t.sgmlDecl += i);
+                            continue;
+                          case T.DOCTYPE:
+                            '>' === i
+                              ? ((t.state = T.TEXT), E(t, 'ondoctype', t.doctype), (t.doctype = !0))
+                              : ((t.doctype += i),
+                                '[' === i
+                                  ? (t.state = T.DOCTYPE_DTD)
+                                  : v(i) && ((t.state = T.DOCTYPE_QUOTED), (t.q = i)));
+                            continue;
+                          case T.DOCTYPE_QUOTED:
+                            (t.doctype += i), i === t.q && ((t.q = ''), (t.state = T.DOCTYPE));
+                            continue;
+                          case T.DOCTYPE_DTD:
+                            (t.doctype += i),
+                              ']' === i ? (t.state = T.DOCTYPE) : v(i) && ((t.state = T.DOCTYPE_DTD_QUOTED), (t.q = i));
+                            continue;
+                          case T.DOCTYPE_DTD_QUOTED:
+                            (t.doctype += i), i === t.q && ((t.state = T.DOCTYPE_DTD), (t.q = ''));
+                            continue;
+                          case T.COMMENT:
+                            '-' === i ? (t.state = T.COMMENT_ENDING) : (t.comment += i);
+                            continue;
+                          case T.COMMENT_ENDING:
+                            '-' === i
+                              ? ((t.state = T.COMMENT_ENDED),
+                                (t.comment = S(t.opt, t.comment)),
+                                t.comment && E(t, 'oncomment', t.comment),
+                                (t.comment = ''))
+                              : ((t.comment += '-' + i), (t.state = T.COMMENT));
+                            continue;
+                          case T.COMMENT_ENDED:
+                            '>' !== i
+                              ? (D(t, 'Malformed comment'), (t.comment += '--' + i), (t.state = T.COMMENT))
+                              : (t.state = T.TEXT);
+                            continue;
+                          case T.CDATA:
+                            ']' === i ? (t.state = T.CDATA_ENDING) : (t.cdata += i);
+                            continue;
+                          case T.CDATA_ENDING:
+                            ']' === i ? (t.state = T.CDATA_ENDING_2) : ((t.cdata += ']' + i), (t.state = T.CDATA));
+                            continue;
+                          case T.CDATA_ENDING_2:
+                            '>' === i
+                              ? (t.cdata && E(t, 'oncdata', t.cdata),
+                                E(t, 'onclosecdata'),
+                                (t.cdata = ''),
+                                (t.state = T.TEXT))
+                              : ']' === i
+                              ? (t.cdata += ']')
+                              : ((t.cdata += ']]' + i), (t.state = T.CDATA));
+                            continue;
+                          case T.PROC_INST:
+                            '?' === i
+                              ? (t.state = T.PROC_INST_ENDING)
+                              : g(i)
+                              ? (t.state = T.PROC_INST_BODY)
+                              : (t.procInstName += i);
+                            continue;
+                          case T.PROC_INST_BODY:
+                            if (!t.procInstBody && g(i)) continue;
+                            '?' === i ? (t.state = T.PROC_INST_ENDING) : (t.procInstBody += i);
+                            continue;
+                          case T.PROC_INST_ENDING:
+                            '>' === i
+                              ? (E(t, 'onprocessinginstruction', { name: t.procInstName, body: t.procInstBody }),
+                                (t.procInstName = t.procInstBody = ''),
+                                (t.state = T.TEXT))
+                              : ((t.procInstBody += '?' + i), (t.state = T.PROC_INST_BODY));
+                            continue;
+                          case T.OPEN_TAG:
+                            j(m, i)
+                              ? (t.tagName += i)
+                              : ((function (e) {
+                                  e.strict || (e.tagName = e.tagName[e.looseCase]());
+                                  var t = e.tags[e.tags.length - 1] || e,
+                                    r = (e.tag = { name: e.tagName, attributes: {} });
+                                  e.opt.xmlns && (r.ns = t.ns);
+                                  (e.attribList.length = 0), E(e, 'onopentagstart', r);
+                                })(t),
+                                '>' === i
+                                  ? N(t)
+                                  : '/' === i
+                                  ? (t.state = T.OPEN_TAG_SLASH)
+                                  : (g(i) || D(t, 'Invalid character in tag name'), (t.state = T.ATTRIB)));
+                            continue;
+                          case T.OPEN_TAG_SLASH:
+                            '>' === i
+                              ? (N(t, !0), R(t))
+                              : (D(t, 'Forward-slash in opening tag not followed by >'), (t.state = T.ATTRIB));
+                            continue;
+                          case T.ATTRIB:
+                            if (g(i)) continue;
+                            '>' === i
+                              ? N(t)
+                              : '/' === i
+                              ? (t.state = T.OPEN_TAG_SLASH)
+                              : j(h, i)
+                              ? ((t.attribName = i), (t.attribValue = ''), (t.state = T.ATTRIB_NAME))
+                              : D(t, 'Invalid attribute name');
+                            continue;
+                          case T.ATTRIB_NAME:
+                            '=' === i
+                              ? (t.state = T.ATTRIB_VALUE)
+                              : '>' === i
+                              ? (D(t, 'Attribute without value'), (t.attribValue = t.attribName), C(t), N(t))
+                              : g(i)
+                              ? (t.state = T.ATTRIB_NAME_SAW_WHITE)
+                              : j(m, i)
+                              ? (t.attribName += i)
+                              : D(t, 'Invalid attribute name');
+                            continue;
+                          case T.ATTRIB_NAME_SAW_WHITE:
+                            if ('=' === i) t.state = T.ATTRIB_VALUE;
+                            else {
+                              if (g(i)) continue;
+                              D(t, 'Attribute without value'),
+                                (t.tag.attributes[t.attribName] = ''),
+                                (t.attribValue = ''),
+                                E(t, 'onattribute', { name: t.attribName, value: '' }),
+                                (t.attribName = ''),
+                                '>' === i
+                                  ? N(t)
+                                  : j(h, i)
+                                  ? ((t.attribName = i), (t.state = T.ATTRIB_NAME))
+                                  : (D(t, 'Invalid attribute name'), (t.state = T.ATTRIB));
+                            }
+                            continue;
+                          case T.ATTRIB_VALUE:
+                            if (g(i)) continue;
+                            v(i)
+                              ? ((t.q = i), (t.state = T.ATTRIB_VALUE_QUOTED))
+                              : (D(t, 'Unquoted attribute value'),
+                                (t.state = T.ATTRIB_VALUE_UNQUOTED),
+                                (t.attribValue = i));
+                            continue;
+                          case T.ATTRIB_VALUE_QUOTED:
+                            if (i !== t.q) {
+                              '&' === i ? (t.state = T.ATTRIB_VALUE_ENTITY_Q) : (t.attribValue += i);
+                              continue;
+                            }
+                            C(t), (t.q = ''), (t.state = T.ATTRIB_VALUE_CLOSED);
+                            continue;
+                          case T.ATTRIB_VALUE_CLOSED:
+                            g(i)
+                              ? (t.state = T.ATTRIB)
+                              : '>' === i
+                              ? N(t)
+                              : '/' === i
+                              ? (t.state = T.OPEN_TAG_SLASH)
+                              : j(h, i)
+                              ? (D(t, 'No whitespace between attributes'),
+                                (t.attribName = i),
+                                (t.attribValue = ''),
+                                (t.state = T.ATTRIB_NAME))
+                              : D(t, 'Invalid attribute name');
+                            continue;
+                          case T.ATTRIB_VALUE_UNQUOTED:
+                            if (
+                              !(function (e) {
+                                return '>' === e || g(e);
+                              })(i)
+                            ) {
+                              '&' === i ? (t.state = T.ATTRIB_VALUE_ENTITY_U) : (t.attribValue += i);
+                              continue;
+                            }
+                            C(t), '>' === i ? N(t) : (t.state = T.ATTRIB);
+                            continue;
+                          case T.CLOSE_TAG:
+                            if (t.tagName)
+                              '>' === i
+                                ? R(t)
+                                : j(m, i)
+                                ? (t.tagName += i)
+                                : t.script
+                                ? ((t.script += '</' + t.tagName), (t.tagName = ''), (t.state = T.SCRIPT))
+                                : (g(i) || D(t, 'Invalid tagname in closing tag'), (t.state = T.CLOSE_TAG_SAW_WHITE));
+                            else {
+                              if (g(i)) continue;
+                              !(function (e, t) {
+                                return !j(e, t);
+                              })(h, i)
+                                ? (t.tagName = i)
+                                : t.script
+                                ? ((t.script += '</' + i), (t.state = T.SCRIPT))
+                                : D(t, 'Invalid tagname in closing tag.');
+                            }
+                            continue;
+                          case T.CLOSE_TAG_SAW_WHITE:
+                            if (g(i)) continue;
+                            '>' === i ? R(t) : D(t, 'Invalid characters in closing tag');
+                            continue;
+                          case T.TEXT_ENTITY:
+                          case T.ATTRIB_VALUE_ENTITY_Q:
+                          case T.ATTRIB_VALUE_ENTITY_U:
+                            switch (t.state) {
+                              case T.TEXT_ENTITY:
+                                (r = T.TEXT), (n = 'textNode');
+                                break;
+                              case T.ATTRIB_VALUE_ENTITY_Q:
+                                (r = T.ATTRIB_VALUE_QUOTED), (n = 'attribValue');
+                                break;
+                              case T.ATTRIB_VALUE_ENTITY_U:
+                                (r = T.ATTRIB_VALUE_UNQUOTED), (n = 'attribValue');
+                            }
+                            ';' === i
+                              ? ((t[n] += (function (e) {
+                                  var t,
+                                    r = e.entity,
+                                    n = r.toLowerCase(),
+                                    s = '';
+                                  if (e.ENTITIES[r]) return e.ENTITIES[r];
+                                  if (e.ENTITIES[n]) return e.ENTITIES[n];
+                                  '#' === (r = n).charAt(0) &&
+                                    (s =
+                                      'x' === r.charAt(1)
+                                        ? ((r = r.slice(2)), (t = parseInt(r, 16)).toString(16))
+                                        : ((r = r.slice(1)), (t = parseInt(r, 10)).toString(10)));
+                                  if (((r = r.replace(/^0+/, '')), isNaN(t) || s.toLowerCase() !== r))
+                                    return D(e, 'Invalid character entity'), '&' + e.entity + ';';
+                                  return String.fromCodePoint(t);
+                                })(t)),
+                                (t.entity = ''),
+                                (t.state = r))
+                              : j(t.entity.length ? b : y, i)
+                              ? (t.entity += i)
+                              : (D(t, 'Invalid character in entity name'),
+                                (t[n] += '&' + t.entity + i),
+                                (t.entity = ''),
+                                (t.state = r));
+                            continue;
+                          default:
+                            throw new Error(t, 'Unknown state: ' + t.state);
+                        }
+                      }
+                      t.position >= t.bufferCheckPosition &&
+                        !(function (e) {
+                          for (var t = Math.max(a.MAX_BUFFER_LENGTH, 10), r = 0, n = 0, s = c.length; n < s; n++) {
+                            var i = e[c[n]].length;
+                            if (t < i)
+                              switch (c[n]) {
+                                case 'textNode':
+                                  _(e);
+                                  break;
+                                case 'cdata':
+                                  E(e, 'oncdata', e.cdata), (e.cdata = '');
+                                  break;
+                                case 'script':
+                                  E(e, 'onscript', e.script), (e.script = '');
+                                  break;
+                                default:
+                                  O(e, 'Max buffer length exceeded: ' + c[n]);
+                              }
+                            r = Math.max(r, i);
+                          }
+                          var o = a.MAX_BUFFER_LENGTH - r;
+                          e.bufferCheckPosition = o + e.position;
+                        })(t);
+                      return t;
+                    },
+                    resume: function () {
+                      return (this.error = null), this;
+                    },
+                    close: function () {
+                      return this.write(null);
+                    },
+                    flush: function () {
+                      var e;
+                      _((e = this)),
+                        '' !== e.cdata && (E(e, 'oncdata', e.cdata), (e.cdata = '')),
+                        '' !== e.script && (E(e, 'onscript', e.script), (e.script = ''));
+                    }
+                  });
+                try {
+                  n = L('stream').Stream;
+                } catch (e) {
+                  n = function () {};
+                }
+                var s = a.EVENTS.filter(function (e) {
+                  return 'error' !== e && 'end' !== e;
+                });
+                function i(e, t) {
+                  if (!(this instanceof i)) return new i(e, t);
+                  n.apply(this), (this._parser = new o(e, t)), (this.writable = !0), (this.readable = !0);
+                  var r = this;
+                  (this._parser.onend = function () {
+                    r.emit('end');
+                  }),
+                    (this._parser.onerror = function (e) {
+                      r.emit('error', e), (r._parser.error = null);
+                    }),
+                    (this._decoder = null),
+                    s.forEach(function (t) {
+                      Object.defineProperty(r, 'on' + t, {
+                        get: function () {
+                          return r._parser['on' + t];
+                        },
+                        set: function (e) {
+                          if (!e) return r.removeAllListeners(t), (r._parser['on' + t] = e);
+                          r.on(t, e);
+                        },
+                        enumerable: !0,
+                        configurable: !1
+                      });
+                    });
+                }
+                ((i.prototype = Object.create(n.prototype, { constructor: { value: i } })).write = function (e) {
+                  var t;
+                  return (
+                    'function' == typeof r &&
+                      'function' == typeof r.isBuffer &&
+                      r.isBuffer(e) &&
+                      (this._decoder || ((t = L('string_decoder').StringDecoder), (this._decoder = new t('utf8'))),
+                      (e = this._decoder.write(e))),
+                    this._parser.write(e.toString()),
+                    this.emit('data', e),
+                    !0
+                  );
+                }),
+                  (i.prototype.end = function (e) {
+                    return e && e.length && this.write(e), this._parser.end(), !0;
+                  }),
+                  (i.prototype.on = function (t, e) {
+                    var r = this;
+                    return (
+                      r._parser['on' + t] ||
+                        -1 === s.indexOf(t) ||
+                        (r._parser['on' + t] = function () {
+                          var e = 1 === arguments.length ? [arguments[0]] : Array.apply(null, arguments);
+                          e.splice(0, 0, t), r.emit.apply(r, e);
+                        }),
+                      n.prototype.on.call(r, t, e)
+                    );
+                  });
+                var l = '[CDATA[',
+                  u = 'DOCTYPE',
+                  p = 'http://www.w3.org/XML/1998/namespace',
+                  f = 'http://www.w3.org/2000/xmlns/',
+                  d = { xml: p, xmlns: f },
+                  h =
+                    /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/,
+                  m =
+                    /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/,
+                  y =
+                    /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/,
+                  b =
+                    /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/;
+                function g(e) {
+                  return ' ' === e || '\n' === e || '\r' === e || '\t' === e;
+                }
+                function v(e) {
+                  return '"' === e || "'" === e;
+                }
+                function j(e, t) {
+                  return e.test(t);
+                }
+                var e,
+                  w,
+                  x,
+                  T = 0;
+                for (e in ((a.STATE = {
+                  BEGIN: T++,
+                  BEGIN_WHITESPACE: T++,
+                  TEXT: T++,
+                  TEXT_ENTITY: T++,
+                  OPEN_WAKA: T++,
+                  SGML_DECL: T++,
+                  SGML_DECL_QUOTED: T++,
+                  DOCTYPE: T++,
+                  DOCTYPE_QUOTED: T++,
+                  DOCTYPE_DTD: T++,
+                  DOCTYPE_DTD_QUOTED: T++,
+                  COMMENT_STARTING: T++,
+                  COMMENT: T++,
+                  COMMENT_ENDING: T++,
+                  COMMENT_ENDED: T++,
+                  CDATA: T++,
+                  CDATA_ENDING: T++,
+                  CDATA_ENDING_2: T++,
+                  PROC_INST: T++,
+                  PROC_INST_BODY: T++,
+                  PROC_INST_ENDING: T++,
+                  OPEN_TAG: T++,
+                  OPEN_TAG_SLASH: T++,
+                  ATTRIB: T++,
+                  ATTRIB_NAME: T++,
+                  ATTRIB_NAME_SAW_WHITE: T++,
+                  ATTRIB_VALUE: T++,
+                  ATTRIB_VALUE_QUOTED: T++,
+                  ATTRIB_VALUE_CLOSED: T++,
+                  ATTRIB_VALUE_UNQUOTED: T++,
+                  ATTRIB_VALUE_ENTITY_Q: T++,
+                  ATTRIB_VALUE_ENTITY_U: T++,
+                  CLOSE_TAG: T++,
+                  CLOSE_TAG_SAW_WHITE: T++,
+                  SCRIPT: T++,
+                  SCRIPT_ENDING: T++
+                }),
+                (a.XML_ENTITIES = { amp: '&', gt: '>', lt: '<', quot: '"', apos: "'" }),
+                (a.ENTITIES = {
+                  amp: '&',
+                  gt: '>',
+                  lt: '<',
+                  quot: '"',
+                  apos: "'",
+                  AElig: 198,
+                  Aacute: 193,
+                  Acirc: 194,
+                  Agrave: 192,
+                  Aring: 197,
+                  Atilde: 195,
+                  Auml: 196,
+                  Ccedil: 199,
+                  ETH: 208,
+                  Eacute: 201,
+                  Ecirc: 202,
+                  Egrave: 200,
+                  Euml: 203,
+                  Iacute: 205,
+                  Icirc: 206,
+                  Igrave: 204,
+                  Iuml: 207,
+                  Ntilde: 209,
+                  Oacute: 211,
+                  Ocirc: 212,
+                  Ograve: 210,
+                  Oslash: 216,
+                  Otilde: 213,
+                  Ouml: 214,
+                  THORN: 222,
+                  Uacute: 218,
+                  Ucirc: 219,
+                  Ugrave: 217,
+                  Uuml: 220,
+                  Yacute: 221,
+                  aacute: 225,
+                  acirc: 226,
+                  aelig: 230,
+                  agrave: 224,
+                  aring: 229,
+                  atilde: 227,
+                  auml: 228,
+                  ccedil: 231,
+                  eacute: 233,
+                  ecirc: 234,
+                  egrave: 232,
+                  eth: 240,
+                  euml: 235,
+                  iacute: 237,
+                  icirc: 238,
+                  igrave: 236,
+                  iuml: 239,
+                  ntilde: 241,
+                  oacute: 243,
+                  ocirc: 244,
+                  ograve: 242,
+                  oslash: 248,
+                  otilde: 245,
+                  ouml: 246,
+                  szlig: 223,
+                  thorn: 254,
+                  uacute: 250,
+                  ucirc: 251,
+                  ugrave: 249,
+                  uuml: 252,
+                  yacute: 253,
+                  yuml: 255,
+                  copy: 169,
+                  reg: 174,
+                  nbsp: 160,
+                  iexcl: 161,
+                  cent: 162,
+                  pound: 163,
+                  curren: 164,
+                  yen: 165,
+                  brvbar: 166,
+                  sect: 167,
+                  uml: 168,
+                  ordf: 170,
+                  laquo: 171,
+                  not: 172,
+                  shy: 173,
+                  macr: 175,
+                  deg: 176,
+                  plusmn: 177,
+                  sup1: 185,
+                  sup2: 178,
+                  sup3: 179,
+                  acute: 180,
+                  micro: 181,
+                  para: 182,
+                  middot: 183,
+                  cedil: 184,
+                  ordm: 186,
+                  raquo: 187,
+                  frac14: 188,
+                  frac12: 189,
+                  frac34: 190,
+                  iquest: 191,
+                  times: 215,
+                  divide: 247,
+                  OElig: 338,
+                  oelig: 339,
+                  Scaron: 352,
+                  scaron: 353,
+                  Yuml: 376,
+                  fnof: 402,
+                  circ: 710,
+                  tilde: 732,
+                  Alpha: 913,
+                  Beta: 914,
+                  Gamma: 915,
+                  Delta: 916,
+                  Epsilon: 917,
+                  Zeta: 918,
+                  Eta: 919,
+                  Theta: 920,
+                  Iota: 921,
+                  Kappa: 922,
+                  Lambda: 923,
+                  Mu: 924,
+                  Nu: 925,
+                  Xi: 926,
+                  Omicron: 927,
+                  Pi: 928,
+                  Rho: 929,
+                  Sigma: 931,
+                  Tau: 932,
+                  Upsilon: 933,
+                  Phi: 934,
+                  Chi: 935,
+                  Psi: 936,
+                  Omega: 937,
+                  alpha: 945,
+                  beta: 946,
+                  gamma: 947,
+                  delta: 948,
+                  epsilon: 949,
+                  zeta: 950,
+                  eta: 951,
+                  theta: 952,
+                  iota: 953,
+                  kappa: 954,
+                  lambda: 955,
+                  mu: 956,
+                  nu: 957,
+                  xi: 958,
+                  omicron: 959,
+                  pi: 960,
+                  rho: 961,
+                  sigmaf: 962,
+                  sigma: 963,
+                  tau: 964,
+                  upsilon: 965,
+                  phi: 966,
+                  chi: 967,
+                  psi: 968,
+                  omega: 969,
+                  thetasym: 977,
+                  upsih: 978,
+                  piv: 982,
+                  ensp: 8194,
+                  emsp: 8195,
+                  thinsp: 8201,
+                  zwnj: 8204,
+                  zwj: 8205,
+                  lrm: 8206,
+                  rlm: 8207,
+                  ndash: 8211,
+                  mdash: 8212,
+                  lsquo: 8216,
+                  rsquo: 8217,
+                  sbquo: 8218,
+                  ldquo: 8220,
+                  rdquo: 8221,
+                  bdquo: 8222,
+                  dagger: 8224,
+                  Dagger: 8225,
+                  bull: 8226,
+                  hellip: 8230,
+                  permil: 8240,
+                  prime: 8242,
+                  Prime: 8243,
+                  lsaquo: 8249,
+                  rsaquo: 8250,
+                  oline: 8254,
+                  frasl: 8260,
+                  euro: 8364,
+                  image: 8465,
+                  weierp: 8472,
+                  real: 8476,
+                  trade: 8482,
+                  alefsym: 8501,
+                  larr: 8592,
+                  uarr: 8593,
+                  rarr: 8594,
+                  darr: 8595,
+                  harr: 8596,
+                  crarr: 8629,
+                  lArr: 8656,
+                  uArr: 8657,
+                  rArr: 8658,
+                  dArr: 8659,
+                  hArr: 8660,
+                  forall: 8704,
+                  part: 8706,
+                  exist: 8707,
+                  empty: 8709,
+                  nabla: 8711,
+                  isin: 8712,
+                  notin: 8713,
+                  ni: 8715,
+                  prod: 8719,
+                  sum: 8721,
+                  minus: 8722,
+                  lowast: 8727,
+                  radic: 8730,
+                  prop: 8733,
+                  infin: 8734,
+                  ang: 8736,
+                  and: 8743,
+                  or: 8744,
+                  cap: 8745,
+                  cup: 8746,
+                  int: 8747,
+                  there4: 8756,
+                  sim: 8764,
+                  cong: 8773,
+                  asymp: 8776,
+                  ne: 8800,
+                  equiv: 8801,
+                  le: 8804,
+                  ge: 8805,
+                  sub: 8834,
+                  sup: 8835,
+                  nsub: 8836,
+                  sube: 8838,
+                  supe: 8839,
+                  oplus: 8853,
+                  otimes: 8855,
+                  perp: 8869,
+                  sdot: 8901,
+                  lceil: 8968,
+                  rceil: 8969,
+                  lfloor: 8970,
+                  rfloor: 8971,
+                  lang: 9001,
+                  rang: 9002,
+                  loz: 9674,
+                  spades: 9824,
+                  clubs: 9827,
+                  hearts: 9829,
+                  diams: 9830
+                }),
+                Object.keys(a.ENTITIES).forEach(function (e) {
+                  var t = a.ENTITIES[e],
+                    t = 'number' == typeof t ? String.fromCharCode(t) : t;
+                  a.ENTITIES[e] = t;
+                }),
+                a.STATE))
+                  a.STATE[a.STATE[e]] = e;
+                function k(e, t, r) {
+                  e[t] && e[t](r);
+                }
+                function E(e, t, r) {
+                  e.textNode && _(e), k(e, t, r);
+                }
+                function _(e) {
+                  (e.textNode = S(e.opt, e.textNode)), e.textNode && k(e, 'ontext', e.textNode), (e.textNode = '');
+                }
+                function S(e, t) {
+                  return e.trim && (t = t.trim()), (t = e.normalize ? t.replace(/\s+/g, ' ') : t);
+                }
+                function O(e, t) {
+                  return (
+                    _(e),
+                    e.trackPosition && (t += '\nLine: ' + e.line + '\nColumn: ' + e.column + '\nChar: ' + e.c),
+                    (t = new Error(t)),
+                    (e.error = t),
+                    k(e, 'onerror', t),
+                    e
+                  );
+                }
+                function A(e) {
+                  return (
+                    e.sawRoot && !e.closedRoot && D(e, 'Unclosed root tag'),
+                    e.state !== T.BEGIN &&
+                      e.state !== T.BEGIN_WHITESPACE &&
+                      e.state !== T.TEXT &&
+                      O(e, 'Unexpected end'),
+                    _(e),
+                    (e.c = ''),
+                    (e.closed = !0),
+                    k(e, 'onend'),
+                    o.call(e, e.strict, e.opt),
+                    e
+                  );
+                }
+                function D(e, t) {
+                  if ('object' != typeof e || !(e instanceof o)) throw new Error('bad call to strictFail');
+                  e.strict && O(e, t);
+                }
+                function I(e, t) {
+                  var r = e.indexOf(':') < 0 ? ['', e] : e.split(':'),
+                    n = r[0],
+                    r = r[1];
+                  return t && 'xmlns' === e && ((n = 'xmlns'), (r = '')), { prefix: n, local: r };
+                }
+                function C(e) {
+                  var t, r, n;
+                  e.strict || (e.attribName = e.attribName[e.looseCase]()),
+                    -1 !== e.attribList.indexOf(e.attribName) ||
+                      e.tag.attributes.hasOwnProperty(e.attribName) ||
+                      (e.opt.xmlns
+                        ? ((r = (t = I(e.attribName, !0)).prefix),
+                          (t = t.local),
+                          'xmlns' === r &&
+                            ('xml' === t && e.attribValue !== p
+                              ? D(e, 'xml: prefix must be bound to ' + p + '\nActual: ' + e.attribValue)
+                              : 'xmlns' === t && e.attribValue !== f
+                              ? D(e, 'xmlns: prefix must be bound to ' + f + '\nActual: ' + e.attribValue)
+                              : ((r = e.tag),
+                                (n = e.tags[e.tags.length - 1] || e),
+                                r.ns === n.ns && (r.ns = Object.create(n.ns)),
+                                (r.ns[t] = e.attribValue))),
+                          e.attribList.push([e.attribName, e.attribValue]))
+                        : ((e.tag.attributes[e.attribName] = e.attribValue),
+                          E(e, 'onattribute', { name: e.attribName, value: e.attribValue }))),
+                    (e.attribName = e.attribValue = '');
+                }
+                function N(t, e) {
+                  if (t.opt.xmlns) {
+                    var r = t.tag,
+                      n = I(t.tagName),
+                      n =
+                        ((r.prefix = n.prefix),
+                        (r.local = n.local),
+                        (r.uri = r.ns[n.prefix] || ''),
+                        r.prefix &&
+                          !r.uri &&
+                          (D(t, 'Unbound namespace prefix: ' + JSON.stringify(t.tagName)), (r.uri = n.prefix)),
+                        t.tags[t.tags.length - 1] || t);
+                    r.ns &&
+                      n.ns !== r.ns &&
+                      Object.keys(r.ns).forEach(function (e) {
+                        E(t, 'onopennamespace', { prefix: e, uri: r.ns[e] });
+                      });
+                    for (var s = 0, i = t.attribList.length; s < i; s++) {
+                      var o = t.attribList[s],
+                        a = o[0],
+                        o = o[1],
+                        c = I(a, !0),
+                        l = c.prefix,
+                        c = c.local,
+                        u = ('' !== l && r.ns[l]) || '',
+                        o = { name: a, value: o, prefix: l, local: c, uri: u };
+                      l && 'xmlns' !== l && !u && (D(t, 'Unbound namespace prefix: ' + JSON.stringify(l)), (o.uri = l)),
+                        (t.tag.attributes[a] = o),
+                        E(t, 'onattribute', o);
+                    }
+                    t.attribList.length = 0;
+                  }
+                  (t.tag.isSelfClosing = !!e),
+                    (t.sawRoot = !0),
+                    t.tags.push(t.tag),
+                    E(t, 'onopentag', t.tag),
+                    e ||
+                      (t.noscript || 'script' !== t.tagName.toLowerCase() ? (t.state = T.TEXT) : (t.state = T.SCRIPT),
+                      (t.tag = null),
+                      (t.tagName = '')),
+                    (t.attribName = t.attribValue = ''),
+                    (t.attribList.length = 0);
+                }
+                function R(r) {
+                  if (!r.tagName) return D(r, 'Weird empty close tag.'), (r.textNode += '</>'), void (r.state = T.TEXT);
+                  if (r.script) {
+                    if ('script' !== r.tagName)
+                      return (r.script += '</' + r.tagName + '>'), (r.tagName = ''), void (r.state = T.SCRIPT);
+                    E(r, 'onscript', r.script), (r.script = '');
+                  }
+                  for (
+                    var e = r.tags.length, t = r.tagName, n = (t = r.strict ? t : t[r.looseCase]());
+                    e-- && r.tags[e].name !== n;
+
+                  )
+                    D(r, 'Unexpected close tag');
+                  if (e < 0)
+                    return (
+                      D(r, 'Unmatched closing tag: ' + r.tagName),
+                      (r.textNode += '</' + r.tagName + '>'),
+                      void (r.state = T.TEXT)
+                    );
+                  r.tagName = t;
+                  for (var s = r.tags.length; s-- > e; ) {
+                    var i,
+                      o = (r.tag = r.tags.pop()),
+                      a = ((r.tagName = r.tag.name), E(r, 'onclosetag', r.tagName), {});
+                    for (i in o.ns) a[i] = o.ns[i];
+                    var c = r.tags[r.tags.length - 1] || r;
+                    r.opt.xmlns &&
+                      o.ns !== c.ns &&
+                      Object.keys(o.ns).forEach(function (e) {
+                        var t = o.ns[e];
+                        E(r, 'onclosenamespace', { prefix: e, uri: t });
+                      });
+                  }
+                  0 === e && (r.closedRoot = !0),
+                    (r.tagName = r.attribValue = r.attribName = ''),
+                    (r.attribList.length = 0),
+                    (r.state = T.TEXT);
+                }
+                function P(e, t) {
+                  '<' === t
+                    ? ((e.state = T.OPEN_WAKA), (e.startTagPosition = e.position))
+                    : g(t) || (D(e, 'Non-whitespace before first tag.'), (e.textNode = t), (e.state = T.TEXT));
+                }
+                function M(e, t) {
+                  var r = '';
+                  return (r = t < e.length ? e.charAt(t) : r);
+                }
+                function t() {
+                  var e = [],
+                    t = -1,
+                    r = arguments.length;
+                  if (!r) return '';
+                  for (var n = ''; ++t < r; ) {
+                    var s = Number(arguments[t]);
+                    if (!isFinite(s) || s < 0 || 1114111 < s || x(s) !== s)
+                      throw RangeError('Invalid code point: ' + s);
+                    s <= 65535 ? e.push(s) : ((s -= 65536), e.push(55296 + (s >> 10), (s % 1024) + 56320)),
+                      (t + 1 === r || 16384 < e.length) && ((n += w.apply(null, e)), (e.length = 0));
+                  }
+                  return n;
+                }
+                (T = a.STATE),
+                  String.fromCodePoint ||
+                    ((w = String.fromCharCode),
+                    (x = Math.floor),
+                    Object.defineProperty
+                      ? Object.defineProperty(String, 'fromCodePoint', { value: t, configurable: !0, writable: !0 })
+                      : (String.fromCodePoint = t));
+              }.call(this);
+            }.call(this, L('buffer').Buffer);
+          },
+          { buffer: 89, stream: 387, string_decoder: 88 }
+        ],
+        387: [
+          function (e, t, r) {
+            t.exports = n;
+            var u = e('events').EventEmitter;
+            function n() {
+              u.call(this);
+            }
+            e('inherits')(n, u),
+              (n.Readable = e('readable-stream/readable.js')),
+              (n.Writable = e('readable-stream/writable.js')),
+              (n.Duplex = e('readable-stream/duplex.js')),
+              (n.Transform = e('readable-stream/transform.js')),
+              (n.PassThrough = e('readable-stream/passthrough.js')),
+              ((n.Stream = n).prototype.pipe = function (t, e) {
+                var r = this;
+                function n(e) {
+                  t.writable && !1 === t.write(e) && r.pause && r.pause();
+                }
+                function s() {
+                  r.readable && r.resume && r.resume();
+                }
+                r.on('data', n),
+                  t.on('drain', s),
+                  t._isStdio || (e && !1 === e.end) || (r.on('end', o), r.on('close', a));
+                var i = !1;
+                function o() {
+                  i || ((i = !0), t.end());
+                }
+                function a() {
+                  i || ((i = !0), 'function' == typeof t.destroy && t.destroy());
+                }
+                function c(e) {
+                  if ((l(), 0 === u.listenerCount(this, 'error'))) throw e;
+                }
+                function l() {
+                  r.removeListener('data', n),
+                    t.removeListener('drain', s),
+                    r.removeListener('end', o),
+                    r.removeListener('close', a),
+                    r.removeListener('error', c),
+                    t.removeListener('error', c),
+                    r.removeListener('end', l),
+                    r.removeListener('close', l),
+                    t.removeListener('close', l);
+                }
+                return (
+                  r.on('error', c),
+                  t.on('error', c),
+                  r.on('end', l),
+                  r.on('close', l),
+                  t.on('close', l),
+                  t.emit('pipe', r),
+                  t
+                );
+              });
+          },
+          {
+            events: 343,
+            inherits: 353,
+            'readable-stream/duplex.js': 371,
+            'readable-stream/passthrough.js': 380,
+            'readable-stream/readable.js': 381,
+            'readable-stream/transform.js': 382,
+            'readable-stream/writable.js': 383
+          }
+        ],
+        388: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('safe-buffer').Buffer,
+              s =
+                n.isEncoding ||
+                function (e) {
+                  switch ((e = '' + e) && e.toLowerCase()) {
+                    case 'hex':
+                    case 'utf8':
+                    case 'utf-8':
+                    case 'ascii':
+                    case 'binary':
+                    case 'base64':
+                    case 'ucs2':
+                    case 'ucs-2':
+                    case 'utf16le':
+                    case 'utf-16le':
+                    case 'raw':
+                      return !0;
+                    default:
+                      return !1;
+                  }
+                };
+            function i(e) {
+              var t = (function (e) {
+                if (!e) return 'utf8';
+                for (var t; ; )
+                  switch (e) {
+                    case 'utf8':
+                    case 'utf-8':
+                      return 'utf8';
+                    case 'ucs2':
+                    case 'ucs-2':
+                    case 'utf16le':
+                    case 'utf-16le':
+                      return 'utf16le';
+                    case 'latin1':
+                    case 'binary':
+                      return 'latin1';
+                    case 'base64':
+                    case 'ascii':
+                    case 'hex':
+                      return e;
+                    default:
+                      if (t) return;
+                      (e = ('' + e).toLowerCase()), (t = !0);
+                  }
+              })(e);
+              if ('string' == typeof t || (n.isEncoding !== s && s(e))) return t || e;
+              throw new Error('Unknown encoding: ' + e);
+            }
+            function o(e) {
+              var t;
+              switch (((this.encoding = i(e)), this.encoding)) {
+                case 'utf16le':
+                  (this.text = l), (this.end = u), (t = 4);
+                  break;
+                case 'utf8':
+                  (this.fillLast = c), (t = 4);
+                  break;
+                case 'base64':
+                  (this.text = p), (this.end = f), (t = 3);
+                  break;
+                default:
+                  return (this.write = d), void (this.end = h);
+              }
+              (this.lastNeed = 0), (this.lastTotal = 0), (this.lastChar = n.allocUnsafe(t));
+            }
+            function a(e) {
+              return e <= 127 ? 0 : e >> 5 == 6 ? 2 : e >> 4 == 14 ? 3 : e >> 3 == 30 ? 4 : e >> 6 == 2 ? -1 : -2;
+            }
+            function c(e) {
+              var t,
+                r = this.lastTotal - this.lastNeed,
+                n =
+                  ((t = this),
+                  128 != (192 & (n = e)[0])
+                    ? ((t.lastNeed = 0), '\ufffd')
+                    : 1 < t.lastNeed && 1 < n.length
+                    ? 128 != (192 & n[1])
+                      ? ((t.lastNeed = 1), '\ufffd')
+                      : 2 < t.lastNeed && 2 < n.length && 128 != (192 & n[2])
+                      ? ((t.lastNeed = 2), '\ufffd')
+                      : void 0
+                    : void 0);
+              return void 0 !== n
+                ? n
+                : this.lastNeed <= e.length
+                ? (e.copy(this.lastChar, r, 0, this.lastNeed), this.lastChar.toString(this.encoding, 0, this.lastTotal))
+                : (e.copy(this.lastChar, r, 0, e.length), void (this.lastNeed -= e.length));
+            }
+            function l(e, t) {
+              if ((e.length - t) % 2 != 0)
+                return (
+                  (this.lastNeed = 1),
+                  (this.lastTotal = 2),
+                  (this.lastChar[0] = e[e.length - 1]),
+                  e.toString('utf16le', t, e.length - 1)
+                );
+              t = e.toString('utf16le', t);
+              if (t) {
+                var r = t.charCodeAt(t.length - 1);
+                if (55296 <= r && r <= 56319)
+                  return (
+                    (this.lastNeed = 2),
+                    (this.lastTotal = 4),
+                    (this.lastChar[0] = e[e.length - 2]),
+                    (this.lastChar[1] = e[e.length - 1]),
+                    t.slice(0, -1)
+                  );
+              }
+              return t;
+            }
+            function u(e) {
+              var t,
+                e = e && e.length ? this.write(e) : '';
+              return this.lastNeed
+                ? ((t = this.lastTotal - this.lastNeed), e + this.lastChar.toString('utf16le', 0, t))
+                : e;
+            }
+            function p(e, t) {
+              var r = (e.length - t) % 3;
+              return 0 == r
+                ? e.toString('base64', t)
+                : ((this.lastNeed = 3 - r),
+                  (this.lastTotal = 3),
+                  1 == r
+                    ? (this.lastChar[0] = e[e.length - 1])
+                    : ((this.lastChar[0] = e[e.length - 2]), (this.lastChar[1] = e[e.length - 1])),
+                  e.toString('base64', t, e.length - r));
+            }
+            function f(e) {
+              e = e && e.length ? this.write(e) : '';
+              return this.lastNeed ? e + this.lastChar.toString('base64', 0, 3 - this.lastNeed) : e;
+            }
+            function d(e) {
+              return e.toString(this.encoding);
+            }
+            function h(e) {
+              return e && e.length ? this.write(e) : '';
+            }
+            ((r.StringDecoder = o).prototype.write = function (e) {
+              if (0 === e.length) return '';
+              var t, r;
+              if (this.lastNeed) {
+                if (void 0 === (t = this.fillLast(e))) return '';
+                (r = this.lastNeed), (this.lastNeed = 0);
+              } else r = 0;
+              return r < e.length ? (t ? t + this.text(e, r) : this.text(e, r)) : t || '';
+            }),
+              (o.prototype.end = function (e) {
+                e = e && e.length ? this.write(e) : '';
+                return this.lastNeed ? e + '\ufffd' : e;
+              }),
+              (o.prototype.text = function (e, t) {
+                var r = (function (e, t, r) {
+                  var n = t.length - 1;
+                  if (n < r) return 0;
+                  var s = a(t[n]);
+                  if (0 <= s) return 0 < s && (e.lastNeed = s - 1), s;
+                  if (--n < r || -2 === s) return 0;
+                  if (0 <= (s = a(t[n]))) return 0 < s && (e.lastNeed = s - 2), s;
+                  if (--n < r || -2 === s) return 0;
+                  if (0 <= (s = a(t[n]))) return 0 < s && (2 === s ? (s = 0) : (e.lastNeed = s - 3)), s;
+                  return 0;
+                })(this, e, t);
+                if (!this.lastNeed) return e.toString('utf8', t);
+                this.lastTotal = r;
+                r = e.length - (r - this.lastNeed);
+                return e.copy(this.lastChar, 0, r), e.toString('utf8', t, r);
+              }),
+              (o.prototype.fillLast = function (e) {
+                if (this.lastNeed <= e.length)
+                  return (
+                    e.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed),
+                    this.lastChar.toString(this.encoding, 0, this.lastTotal)
+                  );
+                e.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, e.length), (this.lastNeed -= e.length);
+              });
+          },
+          { 'safe-buffer': 385 }
+        ],
+        389: [
+          function (c, e, l) {
+            !function (r, a) {
+              !function () {
+                var n = c('process/browser.js').nextTick,
+                  e = Function.prototype.apply,
+                  s = Array.prototype.slice,
+                  i = {},
+                  o = 0;
+                function t(e, t) {
+                  (this._id = e), (this._clearFn = t);
+                }
+                (l.setTimeout = function () {
+                  return new t(e.call(setTimeout, window, arguments), clearTimeout);
+                }),
+                  (l.setInterval = function () {
+                    return new t(e.call(setInterval, window, arguments), clearInterval);
+                  }),
+                  (l.clearTimeout = l.clearInterval =
+                    function (e) {
+                      e.close();
+                    }),
+                  (t.prototype.unref = t.prototype.ref = function () {}),
+                  (t.prototype.close = function () {
+                    this._clearFn.call(window, this._id);
+                  }),
+                  (l.enroll = function (e, t) {
+                    clearTimeout(e._idleTimeoutId), (e._idleTimeout = t);
+                  }),
+                  (l.unenroll = function (e) {
+                    clearTimeout(e._idleTimeoutId), (e._idleTimeout = -1);
+                  }),
+                  (l._unrefActive = l.active =
+                    function (e) {
+                      clearTimeout(e._idleTimeoutId);
+                      var t = e._idleTimeout;
+                      0 <= t &&
+                        (e._idleTimeoutId = setTimeout(function () {
+                          e._onTimeout && e._onTimeout();
+                        }, t));
+                    }),
+                  (l.setImmediate =
+                    'function' == typeof r
+                      ? r
+                      : function (e) {
+                          var t = o++,
+                            r = !(arguments.length < 2) && s.call(arguments, 1);
+                          return (
+                            (i[t] = !0),
+                            n(function () {
+                              i[t] && (r ? e.apply(null, r) : e.call(null), l.clearImmediate(t));
+                            }),
+                            t
+                          );
+                        }),
+                  (l.clearImmediate =
+                    'function' == typeof a
+                      ? a
+                      : function (e) {
+                          delete i[e];
+                        });
+              }.call(this);
+            }.call(this, c('timers').setImmediate, c('timers').clearImmediate);
+          },
+          { 'process/browser.js': 366, timers: 389 }
+        ],
+        390: [
+          function (e, t, r) {
+            var s = e('buffer').Buffer;
+            t.exports = function (e) {
+              if (e instanceof Uint8Array) {
+                if (0 === e.byteOffset && e.byteLength === e.buffer.byteLength) return e.buffer;
+                if ('function' == typeof e.buffer.slice)
+                  return e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength);
+              }
+              if (s.isBuffer(e)) {
+                for (var t = new Uint8Array(e.length), r = e.length, n = 0; n < r; n++) t[n] = e[n];
+                return t.buffer;
+              }
+              throw new Error('Argument must be a Buffer');
+            };
+          },
+          { buffer: 89 }
+        ],
+        391: [
+          function (e, r, t) {
+            !function (t) {
+              !function () {
+                function n(e) {
+                  try {
+                    if (!t.localStorage) return;
+                  } catch (e) {
+                    return;
+                  }
+                  e = t.localStorage[e];
+                  return null != e && 'true' === String(e).toLowerCase();
+                }
+                r.exports = function (e, t) {
+                  if (n('noDeprecation')) return e;
+                  var r = !1;
+                  return function () {
+                    if (!r) {
+                      if (n('throwDeprecation')) throw new Error(t);
+                      n('traceDeprecation') ? console.trace(t) : console.warn(t), (r = !0);
+                    }
+                    return e.apply(this, arguments);
+                  };
+                };
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {}
+        ],
+        392: [
+          function (e, t, r) {
+            arguments[4][82][0].apply(r, arguments);
+          },
+          { dup: 82 }
+        ],
+        393: [
+          function (e, t, r) {
+            arguments[4][83][0].apply(r, arguments);
+          },
+          { dup: 83 }
+        ],
+        394: [
+          function (e, t, r) {
+            arguments[4][84][0].apply(r, arguments);
+          },
+          { './support/isBuffer': 393, _process: 441, dup: 84, inherits: 392 }
+        ],
+        395: [
+          function (e, t, r) {
+            !function () {
+              'use strict';
+              r.stripBOM = function (e) {
+                return '\ufeff' === e[0] ? e.substring(1) : e;
+              };
+            }.call(this);
+          },
+          {}
+        ],
+        396: [
+          function (n, e, i) {
+            !function () {
+              'use strict';
+              var r,
+                s,
+                t,
+                f,
+                d,
+                h = {}.hasOwnProperty;
+              function e(e) {
+                var t, r, n;
+                for (t in ((this.options = {}), (r = s[0.2]))) h.call(r, t) && ((n = r[t]), (this.options[t] = n));
+                for (t in e) h.call(e, t) && ((n = e[t]), (this.options[t] = n));
+              }
+              (r = n('xmlbuilder')),
+                (s = n('./defaults').defaults),
+                (f = function (e) {
+                  return 'string' == typeof e && (0 <= e.indexOf('&') || 0 <= e.indexOf('>') || 0 <= e.indexOf('<'));
+                }),
+                (d = function (e) {
+                  return '<![CDATA[' + t(e) + ']]>';
+                }),
+                (t = function (e) {
+                  return e.replace(']]>', ']]]]><![CDATA[>');
+                }),
+                (i.Builder =
+                  ((e.prototype.buildObject = function (e) {
+                    var c,
+                      t,
+                      l,
+                      u = this.options.attrkey,
+                      p = this.options.charkey;
+                    return (
+                      1 === Object.keys(e).length && this.options.rootName === s[0.2].rootName
+                        ? (e = e[(t = Object.keys(e)[0])])
+                        : (t = this.options.rootName),
+                      (l = this),
+                      (c = function (e, t) {
+                        var r, n, s, i, o, a;
+                        if ('object' != typeof t) l.options.cdata && f(t) ? e.raw(d(t)) : e.txt(t);
+                        else if (Array.isArray(t)) {
+                          for (i in t) if (h.call(t, i)) for (o in (n = t[i])) (s = n[o]), (e = c(e.ele(o), s).up());
+                        } else
+                          for (o in t)
+                            if (h.call(t, o))
+                              if (((n = t[o]), o === u)) {
+                                if ('object' == typeof n) for (r in n) (a = n[r]), (e = e.att(r, a));
+                              } else if (o === p) e = l.options.cdata && f(n) ? e.raw(d(n)) : e.txt(n);
+                              else if (Array.isArray(n))
+                                for (i in n)
+                                  h.call(n, i) &&
+                                    (e = (
+                                      'string' == typeof (s = n[i])
+                                        ? l.options.cdata && f(s)
+                                          ? e.ele(o).raw(d(s))
+                                          : e.ele(o, s)
+                                        : c(e.ele(o), s)
+                                    ).up());
+                              else
+                                e =
+                                  'object' == typeof n
+                                    ? c(e.ele(o), n).up()
+                                    : 'string' == typeof n && l.options.cdata && f(n)
+                                    ? e.ele(o).raw(d(n)).up()
+                                    : (null == n && (n = ''), e.ele(o, n.toString()).up());
+                        return e;
+                      }),
+                      (t = r.create(t, this.options.xmldec, this.options.doctype, {
+                        headless: this.options.headless,
+                        allowSurrogateChars: this.options.allowSurrogateChars
+                      })),
+                      c(t, e).end(this.options.renderOpts)
+                    );
+                  }),
+                  e));
+            }.call(this);
+          },
+          { './defaults': 397, xmlbuilder: 433 }
+        ],
+        397: [
+          function (e, t, r) {
+            !function () {
+              r.defaults = {
+                0.1: {
+                  explicitCharkey: !1,
+                  trim: !0,
+                  normalize: !0,
+                  normalizeTags: !1,
+                  attrkey: '@',
+                  charkey: '#',
+                  explicitArray: !1,
+                  ignoreAttrs: !1,
+                  mergeAttrs: !1,
+                  explicitRoot: !1,
+                  validator: null,
+                  xmlns: !1,
+                  explicitChildren: !1,
+                  childkey: '@@',
+                  charsAsChildren: !1,
+                  includeWhiteChars: !1,
+                  async: !1,
+                  strict: !0,
+                  attrNameProcessors: null,
+                  attrValueProcessors: null,
+                  tagNameProcessors: null,
+                  valueProcessors: null,
+                  emptyTag: ''
+                },
+                0.2: {
+                  explicitCharkey: !1,
+                  trim: !1,
+                  normalize: !1,
+                  normalizeTags: !1,
+                  attrkey: '$',
+                  charkey: '_',
+                  explicitArray: !0,
+                  ignoreAttrs: !1,
+                  mergeAttrs: !1,
+                  explicitRoot: !0,
+                  validator: null,
+                  xmlns: !1,
+                  explicitChildren: !1,
+                  preserveChildrenOrder: !1,
+                  childkey: '$$',
+                  charsAsChildren: !1,
+                  includeWhiteChars: !1,
+                  async: !1,
+                  strict: !0,
+                  attrNameProcessors: null,
+                  attrValueProcessors: null,
+                  tagNameProcessors: null,
+                  valueProcessors: null,
+                  rootName: 'root',
+                  xmldec: { version: '1.0', encoding: 'UTF-8', standalone: !0 },
+                  doctype: null,
+                  renderOpts: { pretty: !0, indent: '  ', newline: '\n' },
+                  headless: !1,
+                  chunkSize: 1e4,
+                  emptyTag: '',
+                  cdata: !1
+                }
+              };
+            }.call(this);
+          },
+          {}
+        ],
+        398: [
+          function (e, t, m) {
+            !function () {
+              'use strict';
+              function i(e, t) {
+                return function () {
+                  return e.apply(t, arguments);
+                };
+              }
+              var f = {}.hasOwnProperty,
+                c = e('sax'),
+                o = e('events'),
+                a = e('./bom'),
+                l = e('./processors'),
+                u = e('timers').setImmediate,
+                p = e('./defaults').defaults,
+                d = function (e) {
+                  return 'object' == typeof e && null != e && 0 === Object.keys(e).length;
+                },
+                h = function (e, t, r) {
+                  for (var n = 0, s = e.length; n < s; n++) t = (0, e[n])(t, r);
+                  return t;
+                };
+              (m.Parser = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) f.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e) {
+                  var t, r, n;
+                  if (
+                    ((this.parseStringPromise = i(this.parseStringPromise, this)),
+                    (this.parseString = i(this.parseString, this)),
+                    (this.reset = i(this.reset, this)),
+                    (this.assignOrPush = i(this.assignOrPush, this)),
+                    (this.processAsync = i(this.processAsync, this)),
+                    !(this instanceof m.Parser))
+                  )
+                    return new m.Parser(e);
+                  for (t in ((this.options = {}), (r = p[0.2]))) f.call(r, t) && ((n = r[t]), (this.options[t] = n));
+                  for (t in e) f.call(e, t) && ((n = e[t]), (this.options[t] = n));
+                  this.options.xmlns && (this.options.xmlnskey = this.options.attrkey + 'ns'),
+                    this.options.normalizeTags &&
+                      (this.options.tagNameProcessors || (this.options.tagNameProcessors = []),
+                      this.options.tagNameProcessors.unshift(l.normalize)),
+                    this.reset();
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.processAsync = function () {
+                    var t;
+                    try {
+                      return this.remaining.length <= this.options.chunkSize
+                        ? ((t = this.remaining),
+                          (this.remaining = ''),
+                          (this.saxParser = this.saxParser.write(t)),
+                          this.saxParser.close())
+                        : ((t = this.remaining.substr(0, this.options.chunkSize)),
+                          (this.remaining = this.remaining.substr(this.options.chunkSize, this.remaining.length)),
+                          (this.saxParser = this.saxParser.write(t)),
+                          u(this.processAsync));
+                    } catch (e) {
+                      if (((t = e), !this.saxParser.errThrown)) return (this.saxParser.errThrown = !0), this.emit(t);
+                    }
+                  }),
+                  (s.prototype.assignOrPush = function (e, t, r) {
+                    return t in e
+                      ? (e[t] instanceof Array || (e[t] = [e[t]]), e[t].push(r))
+                      : this.options.explicitArray
+                      ? (e[t] = [r])
+                      : (e[t] = r);
+                  }),
+                  (s.prototype.reset = function () {
+                    var o, l, t, u, r, e, a, p, n;
+                    return (
+                      this.removeAllListeners(),
+                      (this.saxParser = c.parser(this.options.strict, {
+                        trim: !1,
+                        normalize: !1,
+                        xmlns: this.options.xmlns
+                      })),
+                      (this.saxParser.errThrown = !1),
+                      (this.saxParser.onerror =
+                        ((r = this),
+                        function (e) {
+                          if ((r.saxParser.resume(), !r.saxParser.errThrown))
+                            return (r.saxParser.errThrown = !0), r.emit('error', e);
+                        })),
+                      (this.saxParser.onend =
+                        ((e = this),
+                        function () {
+                          if (!e.saxParser.ended) return (e.saxParser.ended = !0), e.emit('end', e.resultObject);
+                        })),
+                      (this.saxParser.ended = !1),
+                      (this.EXPLICIT_CHARKEY = this.options.explicitCharkey),
+                      (this.resultObject = null),
+                      (u = []),
+                      (o = this.options.attrkey),
+                      (l = this.options.charkey),
+                      (this.saxParser.onopentag =
+                        ((a = this),
+                        function (e) {
+                          var t,
+                            r,
+                            n,
+                            s,
+                            i = {};
+                          if (((i[l] = ''), !a.options.ignoreAttrs))
+                            for (t in (s = e.attributes))
+                              f.call(s, t) &&
+                                (o in i || a.options.mergeAttrs || (i[o] = {}),
+                                (r = a.options.attrValueProcessors
+                                  ? h(a.options.attrValueProcessors, e.attributes[t], t)
+                                  : e.attributes[t]),
+                                (n = a.options.attrNameProcessors ? h(a.options.attrNameProcessors, t) : t),
+                                a.options.mergeAttrs ? a.assignOrPush(i, n, r) : (i[o][n] = r));
+                          return (
+                            (i['#name'] = a.options.tagNameProcessors
+                              ? h(a.options.tagNameProcessors, e.name)
+                              : e.name),
+                            a.options.xmlns && (i[a.options.xmlnskey] = { uri: e.uri, local: e.local }),
+                            u.push(i)
+                          );
+                        })),
+                      (this.saxParser.onclosetag =
+                        ((p = this),
+                        function () {
+                          var e,
+                            t,
+                            n,
+                            r,
+                            s,
+                            i,
+                            o,
+                            a = u.pop(),
+                            c = a['#name'];
+                          if (
+                            ((p.options.explicitChildren && p.options.preserveChildrenOrder) || delete a['#name'],
+                            !0 === a.cdata && ((s = a.cdata), delete a.cdata),
+                            (i = u[u.length - 1]),
+                            a[l].match(/^\s*$/) && !s
+                              ? ((e = a[l]), delete a[l])
+                              : (p.options.trim && (a[l] = a[l].trim()),
+                                p.options.normalize && (a[l] = a[l].replace(/\s{2,}/g, ' ').trim()),
+                                (a[l] = p.options.valueProcessors ? h(p.options.valueProcessors, a[l], c) : a[l]),
+                                1 === Object.keys(a).length && l in a && !p.EXPLICIT_CHARKEY && (a = a[l])),
+                            d(a) && (a = '' !== p.options.emptyTag ? p.options.emptyTag : e),
+                            null != p.options.validator &&
+                              ((o =
+                                '/' +
+                                (function () {
+                                  for (var e = [], t = 0, r = u.length; t < r; t++) (n = u[t]), e.push(n['#name']);
+                                  return e;
+                                })()
+                                  .concat(c)
+                                  .join('/')),
+                              (function () {
+                                try {
+                                  a = p.options.validator(o, i && i[c], a);
+                                } catch (e) {
+                                  return p.emit('error', e);
+                                }
+                              })()),
+                            p.options.explicitChildren && !p.options.mergeAttrs && 'object' == typeof a)
+                          )
+                            if (p.options.preserveChildrenOrder) {
+                              if (i) {
+                                for (t in ((i[p.options.childkey] = i[p.options.childkey] || []), (r = {}), a))
+                                  f.call(a, t) && (r[t] = a[t]);
+                                i[p.options.childkey].push(r),
+                                  delete a['#name'],
+                                  1 === Object.keys(a).length && l in a && !p.EXPLICIT_CHARKEY && (a = a[l]);
+                              }
+                            } else
+                              (n = {}),
+                                p.options.attrkey in a &&
+                                  ((n[p.options.attrkey] = a[p.options.attrkey]), delete a[p.options.attrkey]),
+                                !p.options.charsAsChildren &&
+                                  p.options.charkey in a &&
+                                  ((n[p.options.charkey] = a[p.options.charkey]), delete a[p.options.charkey]),
+                                0 < Object.getOwnPropertyNames(a).length && (n[p.options.childkey] = a),
+                                (a = n);
+                          return 0 < u.length
+                            ? p.assignOrPush(i, c, a)
+                            : (p.options.explicitRoot && ((s = a), ((a = {})[c] = s)),
+                              (p.resultObject = a),
+                              (p.saxParser.ended = !0),
+                              p.emit('end', p.resultObject));
+                        })),
+                      (t = function (e) {
+                        var t,
+                          r = u[u.length - 1];
+                        if (r)
+                          return (
+                            (r[l] += e),
+                            n.options.explicitChildren &&
+                              n.options.preserveChildrenOrder &&
+                              n.options.charsAsChildren &&
+                              (n.options.includeWhiteChars || '' !== e.replace(/\\n/g, '').trim()) &&
+                              ((r[n.options.childkey] = r[n.options.childkey] || []),
+                              ((t = { '#name': '__text__' })[l] = e),
+                              n.options.normalize && (t[l] = t[l].replace(/\s{2,}/g, ' ').trim()),
+                              r[n.options.childkey].push(t)),
+                            r
+                          );
+                      }),
+                      ((n = this).saxParser.ontext = t),
+                      (this.saxParser.oncdata = function (e) {
+                        e = t(e);
+                        if (e) return (e.cdata = !0);
+                      })
+                    );
+                  }),
+                  (s.prototype.parseString = function (t, r) {
+                    null != r &&
+                      'function' == typeof r &&
+                      (this.on('end', function (e) {
+                        return this.reset(), r(null, e);
+                      }),
+                      this.on('error', function (e) {
+                        return this.reset(), r(e);
+                      }));
+                    try {
+                      return '' === (t = t.toString()).trim()
+                        ? (this.emit('end', null), !0)
+                        : ((t = a.stripBOM(t)),
+                          this.options.async
+                            ? ((this.remaining = t), u(this.processAsync), this.saxParser)
+                            : this.saxParser.write(t).close());
+                    } catch (e) {
+                      if (((t = e), !this.saxParser.errThrown && !this.saxParser.ended))
+                        return this.emit('error', t), (this.saxParser.errThrown = !0);
+                      if (this.saxParser.ended) throw t;
+                    }
+                  }),
+                  (s.prototype.parseStringPromise = function (e) {
+                    return new Promise(
+                      ((t = this),
+                      function (r, n) {
+                        return t.parseString(e, function (e, t) {
+                          return e ? n(e) : r(t);
+                        });
+                      })
+                    );
+                    var t;
+                  }),
+                  s
+                );
+              })()),
+                (m.parseString = function (e, t, r) {
+                  var n, s;
+                  return (
+                    null != r
+                      ? ('function' == typeof r && (n = r), 'object' == typeof t && (s = t))
+                      : ('function' == typeof t && (n = t), (s = {})),
+                    new m.Parser(s).parseString(e, n)
+                  );
+                }),
+                (m.parseStringPromise = function (e, t) {
+                  var r;
+                  return new m.Parser((r = 'object' == typeof t ? t : r)).parseStringPromise(e);
+                });
+            }.call(this);
+          },
+          { './bom': 395, './defaults': 397, './processors': 399, events: 343, sax: 386, timers: 389 }
+        ],
+        399: [
+          function (e, t, r) {
+            !function () {
+              'use strict';
+              var t = new RegExp(/(?!xmlns)^.*:/);
+              (r.normalize = function (e) {
+                return e.toLowerCase();
+              }),
+                (r.firstCharLowerCase = function (e) {
+                  return e.charAt(0).toLowerCase() + e.slice(1);
+                }),
+                (r.stripPrefix = function (e) {
+                  return e.replace(t, '');
+                }),
+                (r.parseNumbers = function (e) {
+                  return (e = isNaN(e) ? e : e % 1 == 0 ? parseInt(e, 10) : parseFloat(e));
+                }),
+                (r.parseBooleans = function (e) {
+                  return (e = /^(?:true|false)$/i.test(e) ? 'true' === e.toLowerCase() : e);
+                });
+            }.call(this);
+          },
+          {}
+        ],
+        400: [
+          function (s, e, i) {
+            !function () {
+              'use strict';
+              var o = {}.hasOwnProperty,
+                e = s('./defaults'),
+                t = s('./builder'),
+                r = s('./parser'),
+                n = s('./processors');
+              (i.defaults = e.defaults),
+                (i.processors = n),
+                (i.ValidationError = (function (e) {
+                  var t,
+                    r = i,
+                    n = e;
+                  for (t in n) o.call(n, t) && (r[t] = n[t]);
+                  function s() {
+                    this.constructor = r;
+                  }
+                  function i(e) {
+                    this.message = e;
+                  }
+                  return (s.prototype = n.prototype), (r.prototype = new s()), (r.__super__ = n.prototype), i;
+                })(Error)),
+                (i.Builder = t.Builder),
+                (i.Parser = r.Parser),
+                (i.parseString = r.parseString),
+                (i.parseStringPromise = r.parseStringPromise);
+            }.call(this);
+          },
+          { './builder': 396, './defaults': 397, './parser': 398, './processors': 399 }
+        ],
+        401: [
+          function (e, t, r) {
+            !function () {
+              t.exports = {
+                Disconnected: 1,
+                Preceding: 2,
+                Following: 4,
+                Contains: 8,
+                ContainedBy: 16,
+                ImplementationSpecific: 32
+              };
+            }.call(this);
+          },
+          {}
+        ],
+        402: [
+          function (e, t, r) {
+            !function () {
+              t.exports = {
+                Element: 1,
+                Attribute: 2,
+                Text: 3,
+                CData: 4,
+                EntityReference: 5,
+                EntityDeclaration: 6,
+                ProcessingInstruction: 7,
+                Comment: 8,
+                Document: 9,
+                DocType: 10,
+                DocumentFragment: 11,
+                NotationDeclaration: 12,
+                Declaration: 201,
+                Raw: 202,
+                AttributeDeclaration: 203,
+                ElementDeclaration: 204,
+                Dummy: 205
+              };
+            }.call(this);
+          },
+          {}
+        ],
+        403: [
+          function (e, i, t) {
+            !function () {
+              var o = [].slice,
+                a = {}.hasOwnProperty,
+                c = function (e) {
+                  return !!e && '[object Function]' === Object.prototype.toString.call(e);
+                },
+                t = function (e) {
+                  return !!e && ('function' == (e = typeof e) || 'object' == e);
+                },
+                r = function (e) {
+                  return c(Array.isArray) ? Array.isArray(e) : '[object Array]' === Object.prototype.toString.call(e);
+                },
+                e = function (e) {
+                  if (r(e)) return !e.length;
+                  for (var t in e) if (a.call(e, t)) return !1;
+                  return !0;
+                },
+                n = function (e) {
+                  return (
+                    t(e) &&
+                    (e = Object.getPrototypeOf(e)) &&
+                    (e = e.constructor) &&
+                    'function' == typeof e &&
+                    e instanceof e &&
+                    Function.prototype.toString.call(e) === Function.prototype.toString.call(Object)
+                  );
+                },
+                s = function (e) {
+                  return c(e.valueOf) ? e.valueOf() : e;
+                };
+              (i.exports.assign = function () {
+                var e,
+                  t,
+                  r,
+                  n,
+                  s = arguments[0],
+                  i = 2 <= arguments.length ? o.call(arguments, 1) : [];
+                if (c(Object.assign)) Object.assign.apply(null, arguments);
+                else
+                  for (e = 0, r = i.length; e < r; e++)
+                    if (null != (n = i[e])) for (t in n) a.call(n, t) && (s[t] = n[t]);
+                return s;
+              }),
+                (i.exports.isFunction = c),
+                (i.exports.isObject = t),
+                (i.exports.isArray = r),
+                (i.exports.isEmpty = e),
+                (i.exports.isPlainObject = n),
+                (i.exports.getValue = s);
+            }.call(this);
+          },
+          {}
+        ],
+        404: [
+          function (e, t, r) {
+            !function () {
+              t.exports = { None: 0, OpenTag: 1, InsideTag: 2, CloseTag: 3 };
+            }.call(this);
+          },
+          {}
+        ],
+        405: [
+          function (t, r, e) {
+            !function () {
+              var n;
+              function e(e, t, r) {
+                if (
+                  ((this.parent = e),
+                  this.parent && ((this.options = this.parent.options), (this.stringify = this.parent.stringify)),
+                  null == t)
+                )
+                  throw new Error('Missing attribute name. ' + this.debugInfo(t));
+                (this.name = this.stringify.name(t)),
+                  (this.value = this.stringify.attValue(r)),
+                  (this.type = n.Attribute),
+                  (this.isId = !1),
+                  (this.schemaTypeInfo = null);
+              }
+              (n = t('./NodeType')),
+                t('./XMLNode'),
+                (r.exports =
+                  (Object.defineProperty(e.prototype, 'nodeType', {
+                    get: function () {
+                      return this.type;
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'ownerElement', {
+                    get: function () {
+                      return this.parent;
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'textContent', {
+                    get: function () {
+                      return this.value;
+                    },
+                    set: function (e) {
+                      return (this.value = e || '');
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'namespaceURI', {
+                    get: function () {
+                      return '';
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'prefix', {
+                    get: function () {
+                      return '';
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'localName', {
+                    get: function () {
+                      return this.name;
+                    }
+                  }),
+                  Object.defineProperty(e.prototype, 'specified', {
+                    get: function () {
+                      return !0;
+                    }
+                  }),
+                  (e.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (e.prototype.toString = function (e) {
+                    return this.options.writer.attribute(this, this.options.writer.filterOptions(e));
+                  }),
+                  (e.prototype.debugInfo = function (e) {
+                    return null == (e = e || this.name)
+                      ? 'parent: <' + this.parent.name + '>'
+                      : 'attribute: {' + e + '}, parent: <' + this.parent.name + '>';
+                  }),
+                  (e.prototype.isEqualNode = function (e) {
+                    return (
+                      e.namespaceURI === this.namespaceURI &&
+                      e.prefix === this.prefix &&
+                      e.localName === this.localName &&
+                      e.value === this.value
+                    );
+                  }),
+                  e));
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        406: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./NodeType'),
+                a = e('./XMLCharacterData');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing CDATA text. ' + this.debugInfo());
+                  (this.name = '#cdata-section'), (this.type = o.CData), (this.value = this.stringify.cdata(t));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.cdata(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLCharacterData': 407 }
+        ],
+        407: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./XMLNode');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e) {
+                  s.__super__.constructor.call(this, e), (this.value = '');
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(s.prototype, 'data', {
+                    get: function () {
+                      return this.value;
+                    },
+                    set: function (e) {
+                      return (this.value = e || '');
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'length', {
+                    get: function () {
+                      return this.value.length;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'textContent', {
+                    get: function () {
+                      return this.value;
+                    },
+                    set: function (e) {
+                      return (this.value = e || '');
+                    }
+                  }),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.substringData = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.appendData = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.insertData = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.deleteData = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.replaceData = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.isEqualNode = function (e) {
+                    return !!s.__super__.isEqualNode.apply(this, arguments).isEqualNode(e) && e.data === this.data;
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './XMLNode': 424 }
+        ],
+        408: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./NodeType'),
+                a = e('./XMLCharacterData');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing comment text. ' + this.debugInfo());
+                  (this.name = '#comment'), (this.type = o.Comment), (this.value = this.stringify.comment(t));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.comment(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLCharacterData': 407 }
+        ],
+        409: [
+          function (n, s, e) {
+            !function () {
+              var e, t;
+              function r() {
+                (this.defaultParams = {
+                  'canonical-form': !1,
+                  'cdata-sections': !1,
+                  comments: !1,
+                  'datatype-normalization': !1,
+                  'element-content-whitespace': !0,
+                  entities: !0,
+                  'error-handler': new e(),
+                  infoset: !0,
+                  'validate-if-schema': !1,
+                  namespaces: !0,
+                  'namespace-declarations': !0,
+                  'normalize-characters': !1,
+                  'schema-location': '',
+                  'schema-type': '',
+                  'split-cdata-sections': !0,
+                  validate: !1,
+                  'well-formed': !0
+                }),
+                  (this.params = Object.create(this.defaultParams));
+              }
+              (e = n('./XMLDOMErrorHandler')),
+                (t = n('./XMLDOMStringList')),
+                (s.exports =
+                  (Object.defineProperty(r.prototype, 'parameterNames', {
+                    get: function () {
+                      return new t(Object.keys(this.defaultParams));
+                    }
+                  }),
+                  (r.prototype.getParameter = function (e) {
+                    return this.params.hasOwnProperty(e) ? this.params[e] : null;
+                  }),
+                  (r.prototype.canSetParameter = function (e, t) {
+                    return !0;
+                  }),
+                  (r.prototype.setParameter = function (e, t) {
+                    return null != t ? (this.params[e] = t) : delete this.params[e];
+                  }),
+                  r));
+            }.call(this);
+          },
+          { './XMLDOMErrorHandler': 410, './XMLDOMStringList': 412 }
+        ],
+        410: [
+          function (e, t, r) {
+            !function () {
+              function e() {}
+              t.exports =
+                ((e.prototype.handleError = function (e) {
+                  throw new Error(e);
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        411: [
+          function (e, t, r) {
+            !function () {
+              function e() {}
+              t.exports =
+                ((e.prototype.hasFeature = function (e, t) {
+                  return !0;
+                }),
+                (e.prototype.createDocumentType = function (e, t, r) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                (e.prototype.createDocument = function (e, t, r) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                (e.prototype.createHTMLDocument = function (e) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                (e.prototype.getFeature = function (e, t) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        412: [
+          function (e, t, r) {
+            !function () {
+              function e(e) {
+                this.arr = e || [];
+              }
+              t.exports =
+                (Object.defineProperty(e.prototype, 'length', {
+                  get: function () {
+                    return this.arr.length;
+                  }
+                }),
+                (e.prototype.item = function (e) {
+                  return this.arr[e] || null;
+                }),
+                (e.prototype.contains = function (e) {
+                  return -1 !== this.arr.indexOf(e);
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        413: [
+          function (e, t, r) {
+            !function () {
+              var s = {}.hasOwnProperty,
+                i = e('./XMLNode'),
+                a = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = o,
+                  r = i;
+                for (e in r) s.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function o(e, t, r, n, s, i) {
+                  if ((o.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing DTD element name. ' + this.debugInfo());
+                  if (null == r) throw new Error('Missing DTD attribute name. ' + this.debugInfo(t));
+                  if (!n) throw new Error('Missing DTD attribute type. ' + this.debugInfo(t));
+                  if (!s) throw new Error('Missing DTD attribute default. ' + this.debugInfo(t));
+                  if (!(s = 0 !== s.indexOf('#') ? '#' + s : s).match(/^(#REQUIRED|#IMPLIED|#FIXED|#DEFAULT)$/))
+                    throw new Error(
+                      'Invalid default value type; expected: #REQUIRED, #IMPLIED, #FIXED or #DEFAULT. ' +
+                        this.debugInfo(t)
+                    );
+                  if (i && !s.match(/^(#FIXED|#DEFAULT)$/))
+                    throw new Error('Default value only applies to #FIXED or #DEFAULT. ' + this.debugInfo(t));
+                  (this.elementName = this.stringify.name(t)),
+                    (this.type = a.AttributeDeclaration),
+                    (this.attributeName = this.stringify.name(r)),
+                    (this.attributeType = this.stringify.dtdAttType(n)),
+                    i && (this.defaultValue = this.stringify.dtdAttDefault(i)),
+                    (this.defaultValueType = s);
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (o.prototype.toString = function (e) {
+                    return this.options.writer.dtdAttList(this, this.options.writer.filterOptions(e));
+                  }),
+                  o
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        414: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./XMLNode'),
+                a = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t, r) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing DTD element name. ' + this.debugInfo());
+                  (r = r || '(#PCDATA)'),
+                    Array.isArray(r) && (r = '(' + r.join(',') + ')'),
+                    (this.name = this.stringify.name(t)),
+                    (this.type = a.ElementDeclaration),
+                    (this.value = this.stringify.dtdElementValue(r));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.dtdElement(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        415: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./Utility').isObject,
+                a = e('./XMLNode'),
+                c = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t, r, n) {
+                  if ((s.__super__.constructor.call(this, e), null == r))
+                    throw new Error('Missing DTD entity name. ' + this.debugInfo(r));
+                  if (null == n) throw new Error('Missing DTD entity value. ' + this.debugInfo(r));
+                  if (
+                    ((this.pe = !!t), (this.name = this.stringify.name(r)), (this.type = c.EntityDeclaration), o(n))
+                  ) {
+                    if (!n.pubID && !n.sysID)
+                      throw new Error(
+                        'Public and/or system identifiers are required for an external entity. ' + this.debugInfo(r)
+                      );
+                    if (n.pubID && !n.sysID)
+                      throw new Error(
+                        'System identifier is required for a public external entity. ' + this.debugInfo(r)
+                      );
+                    if (
+                      ((this.internal = !1),
+                      null != n.pubID && (this.pubID = this.stringify.dtdPubID(n.pubID)),
+                      null != n.sysID && (this.sysID = this.stringify.dtdSysID(n.sysID)),
+                      null != n.nData && (this.nData = this.stringify.dtdNData(n.nData)),
+                      this.pe && this.nData)
+                    )
+                      throw new Error(
+                        'Notation declaration is not allowed in a parameter entity. ' + this.debugInfo(r)
+                      );
+                  } else (this.value = this.stringify.dtdEntityValue(n)), (this.internal = !0);
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(s.prototype, 'publicId', {
+                    get: function () {
+                      return this.pubID;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'systemId', {
+                    get: function () {
+                      return this.sysID;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'notationName', {
+                    get: function () {
+                      return this.nData || null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'inputEncoding', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'xmlEncoding', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'xmlVersion', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.dtdEntity(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './Utility': 403, './XMLNode': 424 }
+        ],
+        416: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./XMLNode'),
+                a = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t, r) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing DTD notation name. ' + this.debugInfo(t));
+                  if (!r.pubID && !r.sysID)
+                    throw new Error(
+                      'Public or system identifiers are required for an external entity. ' + this.debugInfo(t)
+                    );
+                  (this.name = this.stringify.name(t)),
+                    (this.type = a.NotationDeclaration),
+                    null != r.pubID && (this.pubID = this.stringify.dtdPubID(r.pubID)),
+                    null != r.sysID && (this.sysID = this.stringify.dtdSysID(r.sysID));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(s.prototype, 'publicId', {
+                    get: function () {
+                      return this.pubID;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'systemId', {
+                    get: function () {
+                      return this.sysID;
+                    }
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.dtdNotation(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        417: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./Utility').isObject,
+                a = e('./XMLNode'),
+                c = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t, r, n) {
+                  s.__super__.constructor.call(this, e),
+                    o(t) && ((t = (e = t).version), (r = e.encoding), (n = e.standalone)),
+                    (t = t || '1.0'),
+                    (this.type = c.Declaration),
+                    (this.version = this.stringify.xmlVersion(t)),
+                    null != r && (this.encoding = this.stringify.xmlEncoding(r)),
+                    null != n && (this.standalone = this.stringify.xmlStandalone(n));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.declaration(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './Utility': 403, './XMLNode': 424 }
+        ],
+        418: [
+          function (e, t, r) {
+            !function () {
+              var s = {}.hasOwnProperty,
+                c = e('./Utility').isObject,
+                i = e('./XMLNode'),
+                l = e('./NodeType'),
+                o = e('./XMLDTDAttList'),
+                u = e('./XMLDTDEntity'),
+                p = e('./XMLDTDElement'),
+                f = e('./XMLDTDNotation'),
+                d = e('./XMLNamedNodeMap');
+              t.exports = (function () {
+                var e,
+                  t = a,
+                  r = i;
+                for (e in r) s.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function a(e, t, r) {
+                  var n, s, i, o;
+                  if ((a.__super__.constructor.call(this, e), (this.type = l.DocType), e.children))
+                    for (s = 0, i = (o = e.children).length; s < i; s++)
+                      if ((n = o[s]).type === l.Element) {
+                        this.name = n.name;
+                        break;
+                      }
+                  (this.documentObject = e),
+                    c(t) && ((t = (e = t).pubID), (r = e.sysID)),
+                    null == r && ((r = (e = [t, r])[0]), (t = e[1])),
+                    null != t && (this.pubID = this.stringify.dtdPubID(t)),
+                    null != r && (this.sysID = this.stringify.dtdSysID(r));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(a.prototype, 'entities', {
+                    get: function () {
+                      for (var e, t = {}, r = this.children, n = 0, s = r.length; n < s; n++)
+                        (e = r[n]).type !== l.EntityDeclaration || e.pe || (t[e.name] = e);
+                      return new d(t);
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'notations', {
+                    get: function () {
+                      for (var e, t = {}, r = this.children, n = 0, s = r.length; n < s; n++)
+                        (e = r[n]).type === l.NotationDeclaration && (t[e.name] = e);
+                      return new d(t);
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'publicId', {
+                    get: function () {
+                      return this.pubID;
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'systemId', {
+                    get: function () {
+                      return this.sysID;
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'internalSubset', {
+                    get: function () {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  (a.prototype.element = function (e, t) {
+                    e = new p(this, e, t);
+                    return this.children.push(e), this;
+                  }),
+                  (a.prototype.attList = function (e, t, r, n, s) {
+                    e = new o(this, e, t, r, n, s);
+                    return this.children.push(e), this;
+                  }),
+                  (a.prototype.entity = function (e, t) {
+                    e = new u(this, !1, e, t);
+                    return this.children.push(e), this;
+                  }),
+                  (a.prototype.pEntity = function (e, t) {
+                    e = new u(this, !0, e, t);
+                    return this.children.push(e), this;
+                  }),
+                  (a.prototype.notation = function (e, t) {
+                    e = new f(this, e, t);
+                    return this.children.push(e), this;
+                  }),
+                  (a.prototype.toString = function (e) {
+                    return this.options.writer.docType(this, this.options.writer.filterOptions(e));
+                  }),
+                  (a.prototype.ele = function (e, t) {
+                    return this.element(e, t);
+                  }),
+                  (a.prototype.att = function (e, t, r, n, s) {
+                    return this.attList(e, t, r, n, s);
+                  }),
+                  (a.prototype.ent = function (e, t) {
+                    return this.entity(e, t);
+                  }),
+                  (a.prototype.pent = function (e, t) {
+                    return this.pEntity(e, t);
+                  }),
+                  (a.prototype.not = function (e, t) {
+                    return this.notation(e, t);
+                  }),
+                  (a.prototype.up = function () {
+                    return this.root() || this.documentObject;
+                  }),
+                  (a.prototype.isEqualNode = function (e) {
+                    return (
+                      !!a.__super__.isEqualNode.apply(this, arguments).isEqualNode(e) &&
+                      e.name === this.name &&
+                      e.publicId === this.publicId &&
+                      e.systemId === this.systemId
+                    );
+                  }),
+                  a
+                );
+              })();
+            }.call(this);
+          },
+          {
+            './NodeType': 402,
+            './Utility': 403,
+            './XMLDTDAttList': 413,
+            './XMLDTDElement': 414,
+            './XMLDTDEntity': 415,
+            './XMLDTDNotation': 416,
+            './XMLNamedNodeMap': 423,
+            './XMLNode': 424
+          }
+        ],
+        419: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./Utility').isPlainObject,
+                a = e('./XMLDOMImplementation'),
+                c = e('./XMLDOMConfiguration'),
+                l = e('./XMLNode'),
+                u = e('./NodeType'),
+                p = e('./XMLStringifier'),
+                f = e('./XMLStringWriter');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = l;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e) {
+                  s.__super__.constructor.call(this, null),
+                    (this.name = '#document'),
+                    (this.type = u.Document),
+                    (this.documentURI = null),
+                    (this.domConfig = new c()),
+                    (e = e || {}).writer || (e.writer = new f()),
+                    (this.options = e),
+                    (this.stringify = new p(e));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(s.prototype, 'implementation', { value: new a() }),
+                  Object.defineProperty(s.prototype, 'doctype', {
+                    get: function () {
+                      for (var e, t = this.children, r = 0, n = t.length; r < n; r++)
+                        if ((e = t[r]).type === u.DocType) return e;
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'documentElement', {
+                    get: function () {
+                      return this.rootObject || null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'inputEncoding', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'strictErrorChecking', {
+                    get: function () {
+                      return !1;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'xmlEncoding', {
+                    get: function () {
+                      return 0 !== this.children.length && this.children[0].type === u.Declaration
+                        ? this.children[0].encoding
+                        : null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'xmlStandalone', {
+                    get: function () {
+                      return (
+                        0 !== this.children.length &&
+                        this.children[0].type === u.Declaration &&
+                        'yes' === this.children[0].standalone
+                      );
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'xmlVersion', {
+                    get: function () {
+                      return 0 !== this.children.length && this.children[0].type === u.Declaration
+                        ? this.children[0].version
+                        : '1.0';
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'URL', {
+                    get: function () {
+                      return this.documentURI;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'origin', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'compatMode', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'characterSet', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'contentType', {
+                    get: function () {
+                      return null;
+                    }
+                  }),
+                  (s.prototype.end = function (e) {
+                    var t = {};
+                    return (
+                      e ? o(e) && ((t = e), (e = this.options.writer)) : (e = this.options.writer),
+                      e.document(this, e.filterOptions(t))
+                    );
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.document(this, this.options.writer.filterOptions(e));
+                  }),
+                  (s.prototype.createElement = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createDocumentFragment = function () {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createTextNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createComment = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createCDATASection = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createProcessingInstruction = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createAttribute = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createEntityReference = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.getElementsByTagName = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.importNode = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createElementNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createAttributeNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.getElementsByTagNameNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.getElementById = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.adoptNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.normalizeDocument = function () {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.renameNode = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.getElementsByClassName = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createEvent = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createRange = function () {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createNodeIterator = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.createTreeWalker = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          {
+            './NodeType': 402,
+            './Utility': 403,
+            './XMLDOMConfiguration': 409,
+            './XMLDOMImplementation': 411,
+            './XMLNode': 424,
+            './XMLStringWriter': 429,
+            './XMLStringifier': 430
+          }
+        ],
+        420: [
+          function (E, _, e) {
+            !function () {
+              var l,
+                i,
+                s,
+                t,
+                r,
+                o,
+                n,
+                a,
+                c,
+                u,
+                p,
+                f,
+                d,
+                h,
+                m,
+                y,
+                b,
+                g,
+                v,
+                j,
+                w,
+                x,
+                e,
+                T = {}.hasOwnProperty;
+              function k(e, t, r) {
+                var n;
+                (this.name = '?xml'),
+                  (this.type = l.Document),
+                  (n = {}),
+                  (e = e || {}).writer ? x(e.writer) && ((n = e.writer), (e.writer = new y())) : (e.writer = new y()),
+                  (this.options = e),
+                  (this.writer = e.writer),
+                  (this.writerOptions = this.writer.filterOptions(n)),
+                  (this.stringify = new b(e)),
+                  (this.onDataCallback = t || function () {}),
+                  (this.onEndCallback = r || function () {}),
+                  (this.currentNode = null),
+                  (this.currentLevel = -1),
+                  (this.openTags = {}),
+                  (this.documentStarted = !1),
+                  (this.documentCompleted = !1),
+                  (this.root = null);
+              }
+              (e = E('./Utility')),
+                (w = e.isObject),
+                (j = e.isFunction),
+                (x = e.isPlainObject),
+                (v = e.getValue),
+                (l = E('./NodeType')),
+                (f = E('./XMLDocument')),
+                (d = E('./XMLElement')),
+                (t = E('./XMLCData')),
+                (r = E('./XMLComment')),
+                (m = E('./XMLRaw')),
+                (g = E('./XMLText')),
+                (h = E('./XMLProcessingInstruction')),
+                (u = E('./XMLDeclaration')),
+                (p = E('./XMLDocType')),
+                (o = E('./XMLDTDAttList')),
+                (a = E('./XMLDTDEntity')),
+                (n = E('./XMLDTDElement')),
+                (c = E('./XMLDTDNotation')),
+                (s = E('./XMLAttribute')),
+                (b = E('./XMLStringifier')),
+                (y = E('./XMLStringWriter')),
+                (i = E('./WriterState')),
+                (_.exports =
+                  ((k.prototype.createChildNode = function (e) {
+                    var t, r, n, s, i, o, a, c;
+                    switch (e.type) {
+                      case l.CData:
+                        this.cdata(e.value);
+                        break;
+                      case l.Comment:
+                        this.comment(e.value);
+                        break;
+                      case l.Element:
+                        for (r in ((n = {}), (a = e.attribs))) T.call(a, r) && ((t = a[r]), (n[r] = t.value));
+                        this.node(e.name, n);
+                        break;
+                      case l.Dummy:
+                        this.dummy();
+                        break;
+                      case l.Raw:
+                        this.raw(e.value);
+                        break;
+                      case l.Text:
+                        this.text(e.value);
+                        break;
+                      case l.ProcessingInstruction:
+                        this.instruction(e.target, e.value);
+                        break;
+                      default:
+                        throw new Error('This XML node type is not supported in a JS object: ' + e.constructor.name);
+                    }
+                    for (i = 0, o = (c = e.children).length; i < o; i++)
+                      (s = c[i]), this.createChildNode(s), s.type === l.Element && this.up();
+                    return this;
+                  }),
+                  (k.prototype.dummy = function () {
+                    return this;
+                  }),
+                  (k.prototype.node = function (e, t, r) {
+                    var n;
+                    if (null == e) throw new Error('Missing node name.');
+                    if (this.root && -1 === this.currentLevel)
+                      throw new Error('Document can only have one root node. ' + this.debugInfo(e));
+                    return (
+                      this.openCurrent(),
+                      (e = v(e)),
+                      (t = v((t = null == t ? {} : t))),
+                      w(t) || ((r = (n = [t, r])[0]), (t = n[1])),
+                      (this.currentNode = new d(this, e, t)),
+                      (this.currentNode.children = !1),
+                      this.currentLevel++,
+                      (this.openTags[this.currentLevel] = this.currentNode),
+                      null != r && this.text(r),
+                      this
+                    );
+                  }),
+                  (k.prototype.element = function (e, t, r) {
+                    var n, s, i, o, a, c;
+                    if (this.currentNode && this.currentNode.type === l.DocType) this.dtdElement.apply(this, arguments);
+                    else if (Array.isArray(e) || w(e) || j(e))
+                      for (
+                        o = this.options.noValidation,
+                          this.options.noValidation = !0,
+                          (c = new f(this.options).element('TEMP_ROOT')).element(e),
+                          this.options.noValidation = o,
+                          s = 0,
+                          i = (a = c.children).length;
+                        s < i;
+                        s++
+                      )
+                        (n = a[s]), this.createChildNode(n), n.type === l.Element && this.up();
+                    else this.node(e, t, r);
+                    return this;
+                  }),
+                  (k.prototype.attribute = function (e, t) {
+                    var r, n;
+                    if (!this.currentNode || this.currentNode.children)
+                      throw new Error(
+                        'att() can only be used immediately after an ele() call in callback mode. ' + this.debugInfo(e)
+                      );
+                    if ((null != e && (e = v(e)), w(e)))
+                      for (r in e) T.call(e, r) && ((n = e[r]), this.attribute(r, n));
+                    else
+                      j(t) && (t = t.apply()),
+                        this.options.keepNullAttributes && null == t
+                          ? (this.currentNode.attribs[e] = new s(this, e, ''))
+                          : null != t && (this.currentNode.attribs[e] = new s(this, e, t));
+                    return this;
+                  }),
+                  (k.prototype.text = function (e) {
+                    return (
+                      this.openCurrent(),
+                      (e = new g(this, e)),
+                      this.onData(
+                        this.writer.text(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.cdata = function (e) {
+                    return (
+                      this.openCurrent(),
+                      (e = new t(this, e)),
+                      this.onData(
+                        this.writer.cdata(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.comment = function (e) {
+                    return (
+                      this.openCurrent(),
+                      (e = new r(this, e)),
+                      this.onData(
+                        this.writer.comment(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.raw = function (e) {
+                    return (
+                      this.openCurrent(),
+                      (e = new m(this, e)),
+                      this.onData(this.writer.raw(e, this.writerOptions, this.currentLevel + 1), this.currentLevel + 1),
+                      this
+                    );
+                  }),
+                  (k.prototype.instruction = function (e, t) {
+                    var r, n, s, i;
+                    if ((this.openCurrent(), null != e && (e = v(e)), null != t && (t = v(t)), Array.isArray(e)))
+                      for (r = 0, i = e.length; r < i; r++) (n = e[r]), this.instruction(n);
+                    else if (w(e)) for (n in e) T.call(e, n) && ((s = e[n]), this.instruction(n, s));
+                    else
+                      j(t) && (t = t.apply()),
+                        (t = new h(this, e, t)),
+                        this.onData(
+                          this.writer.processingInstruction(t, this.writerOptions, this.currentLevel + 1),
+                          this.currentLevel + 1
+                        );
+                    return this;
+                  }),
+                  (k.prototype.declaration = function (e, t, r) {
+                    if ((this.openCurrent(), this.documentStarted))
+                      throw new Error('declaration() must be the first node.');
+                    return (
+                      (e = new u(this, e, t, r)),
+                      this.onData(
+                        this.writer.declaration(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.doctype = function (e, t, r) {
+                    if ((this.openCurrent(), null == e)) throw new Error('Missing root node name.');
+                    if (this.root) throw new Error('dtd() must come before the root node.');
+                    return (
+                      (this.currentNode = new p(this, t, r)),
+                      (this.currentNode.rootNodeName = e),
+                      (this.currentNode.children = !1),
+                      this.currentLevel++,
+                      (this.openTags[this.currentLevel] = this.currentNode),
+                      this
+                    );
+                  }),
+                  (k.prototype.dtdElement = function (e, t) {
+                    return (
+                      this.openCurrent(),
+                      (e = new n(this, e, t)),
+                      this.onData(
+                        this.writer.dtdElement(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.attList = function (e, t, r, n, s) {
+                    return (
+                      this.openCurrent(),
+                      (e = new o(this, e, t, r, n, s)),
+                      this.onData(
+                        this.writer.dtdAttList(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.entity = function (e, t) {
+                    return (
+                      this.openCurrent(),
+                      (e = new a(this, !1, e, t)),
+                      this.onData(
+                        this.writer.dtdEntity(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.pEntity = function (e, t) {
+                    return (
+                      this.openCurrent(),
+                      (e = new a(this, !0, e, t)),
+                      this.onData(
+                        this.writer.dtdEntity(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.notation = function (e, t) {
+                    return (
+                      this.openCurrent(),
+                      (e = new c(this, e, t)),
+                      this.onData(
+                        this.writer.dtdNotation(e, this.writerOptions, this.currentLevel + 1),
+                        this.currentLevel + 1
+                      ),
+                      this
+                    );
+                  }),
+                  (k.prototype.up = function () {
+                    if (this.currentLevel < 0) throw new Error('The document node has no parent.');
+                    return (
+                      this.currentNode
+                        ? (this.currentNode.children
+                            ? this.closeNode(this.currentNode)
+                            : this.openNode(this.currentNode),
+                          (this.currentNode = null))
+                        : this.closeNode(this.openTags[this.currentLevel]),
+                      delete this.openTags[this.currentLevel],
+                      this.currentLevel--,
+                      this
+                    );
+                  }),
+                  (k.prototype.end = function () {
+                    for (; 0 <= this.currentLevel; ) this.up();
+                    return this.onEnd();
+                  }),
+                  (k.prototype.openCurrent = function () {
+                    if (this.currentNode) return (this.currentNode.children = !0), this.openNode(this.currentNode);
+                  }),
+                  (k.prototype.openNode = function (e) {
+                    var t, r, n, s;
+                    if (!e.isOpen) {
+                      if (
+                        (this.root || 0 !== this.currentLevel || e.type !== l.Element || (this.root = e),
+                        (r = ''),
+                        e.type === l.Element)
+                      ) {
+                        for (n in ((this.writerOptions.state = i.OpenTag),
+                        (r = this.writer.indent(e, this.writerOptions, this.currentLevel) + '<' + e.name),
+                        (s = e.attribs)))
+                          T.call(s, n) &&
+                            ((t = s[n]), (r += this.writer.attribute(t, this.writerOptions, this.currentLevel)));
+                        (r +=
+                          (e.children ? '>' : '/>') + this.writer.endline(e, this.writerOptions, this.currentLevel)),
+                          (this.writerOptions.state = i.InsideTag);
+                      } else
+                        (this.writerOptions.state = i.OpenTag),
+                          (r =
+                            this.writer.indent(e, this.writerOptions, this.currentLevel) +
+                            '<!DOCTYPE ' +
+                            e.rootNodeName),
+                          e.pubID && e.sysID
+                            ? (r += ' PUBLIC "' + e.pubID + '" "' + e.sysID + '"')
+                            : e.sysID && (r += ' SYSTEM "' + e.sysID + '"'),
+                          e.children
+                            ? ((r += ' ['), (this.writerOptions.state = i.InsideTag))
+                            : ((this.writerOptions.state = i.CloseTag), (r += '>')),
+                          (r += this.writer.endline(e, this.writerOptions, this.currentLevel));
+                      return this.onData(r, this.currentLevel), (e.isOpen = !0);
+                    }
+                  }),
+                  (k.prototype.closeNode = function (e) {
+                    var t;
+                    if (!e.isClosed)
+                      return (
+                        (t = ''),
+                        (this.writerOptions.state = i.CloseTag),
+                        (t =
+                          e.type === l.Element
+                            ? this.writer.indent(e, this.writerOptions, this.currentLevel) +
+                              '</' +
+                              e.name +
+                              '>' +
+                              this.writer.endline(e, this.writerOptions, this.currentLevel)
+                            : this.writer.indent(e, this.writerOptions, this.currentLevel) +
+                              ']>' +
+                              this.writer.endline(e, this.writerOptions, this.currentLevel)),
+                        (this.writerOptions.state = i.None),
+                        this.onData(t, this.currentLevel),
+                        (e.isClosed = !0)
+                      );
+                  }),
+                  (k.prototype.onData = function (e, t) {
+                    return (this.documentStarted = !0), this.onDataCallback(e, t + 1);
+                  }),
+                  (k.prototype.onEnd = function () {
+                    return (this.documentCompleted = !0), this.onEndCallback();
+                  }),
+                  (k.prototype.debugInfo = function (e) {
+                    return null == e ? '' : 'node: <' + e + '>';
+                  }),
+                  (k.prototype.ele = function () {
+                    return this.element.apply(this, arguments);
+                  }),
+                  (k.prototype.nod = function (e, t, r) {
+                    return this.node(e, t, r);
+                  }),
+                  (k.prototype.txt = function (e) {
+                    return this.text(e);
+                  }),
+                  (k.prototype.dat = function (e) {
+                    return this.cdata(e);
+                  }),
+                  (k.prototype.com = function (e) {
+                    return this.comment(e);
+                  }),
+                  (k.prototype.ins = function (e, t) {
+                    return this.instruction(e, t);
+                  }),
+                  (k.prototype.dec = function (e, t, r) {
+                    return this.declaration(e, t, r);
+                  }),
+                  (k.prototype.dtd = function (e, t, r) {
+                    return this.doctype(e, t, r);
+                  }),
+                  (k.prototype.e = function (e, t, r) {
+                    return this.element(e, t, r);
+                  }),
+                  (k.prototype.n = function (e, t, r) {
+                    return this.node(e, t, r);
+                  }),
+                  (k.prototype.t = function (e) {
+                    return this.text(e);
+                  }),
+                  (k.prototype.d = function (e) {
+                    return this.cdata(e);
+                  }),
+                  (k.prototype.c = function (e) {
+                    return this.comment(e);
+                  }),
+                  (k.prototype.r = function (e) {
+                    return this.raw(e);
+                  }),
+                  (k.prototype.i = function (e, t) {
+                    return this.instruction(e, t);
+                  }),
+                  (k.prototype.att = function () {
+                    return (
+                      this.currentNode && this.currentNode.type === l.DocType ? this.attList : this.attribute
+                    ).apply(this, arguments);
+                  }),
+                  (k.prototype.a = function () {
+                    return (
+                      this.currentNode && this.currentNode.type === l.DocType ? this.attList : this.attribute
+                    ).apply(this, arguments);
+                  }),
+                  (k.prototype.ent = function (e, t) {
+                    return this.entity(e, t);
+                  }),
+                  (k.prototype.pent = function (e, t) {
+                    return this.pEntity(e, t);
+                  }),
+                  (k.prototype.not = function (e, t) {
+                    return this.notation(e, t);
+                  }),
+                  k));
+            }.call(this);
+          },
+          {
+            './NodeType': 402,
+            './Utility': 403,
+            './WriterState': 404,
+            './XMLAttribute': 405,
+            './XMLCData': 406,
+            './XMLComment': 408,
+            './XMLDTDAttList': 413,
+            './XMLDTDElement': 414,
+            './XMLDTDEntity': 415,
+            './XMLDTDNotation': 416,
+            './XMLDeclaration': 417,
+            './XMLDocType': 418,
+            './XMLDocument': 419,
+            './XMLElement': 422,
+            './XMLProcessingInstruction': 426,
+            './XMLRaw': 427,
+            './XMLStringWriter': 429,
+            './XMLStringifier': 430,
+            './XMLText': 431
+          }
+        ],
+        421: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./XMLNode'),
+                a = e('./NodeType');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e) {
+                  s.__super__.constructor.call(this, e), (this.type = a.Dummy);
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return '';
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        422: [
+          function (t, r, e) {
+            !function () {
+              var s = {}.hasOwnProperty,
+                e = t('./Utility'),
+                i = e.isObject,
+                o = e.isFunction,
+                c = e.getValue,
+                l = t('./XMLNode'),
+                u = t('./NodeType'),
+                p = t('./XMLAttribute'),
+                f = t('./XMLNamedNodeMap');
+              r.exports = (function () {
+                var e,
+                  t = a,
+                  r = l;
+                for (e in r) s.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function a(e, t, r) {
+                  var n, s, i, o;
+                  if ((a.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing element name. ' + this.debugInfo());
+                  if (
+                    ((this.name = this.stringify.name(t)),
+                    (this.type = u.Element),
+                    (this.attribs = {}),
+                    (this.schemaTypeInfo = null) != r && this.attribute(r),
+                    e.type === u.Document &&
+                      ((this.isRoot = !0), ((this.documentObject = e).rootObject = this), e.children))
+                  )
+                    for (s = 0, i = (o = e.children).length; s < i; s++)
+                      if ((n = o[s]).type === u.DocType) {
+                        n.name = this.name;
+                        break;
+                      }
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(a.prototype, 'tagName', {
+                    get: function () {
+                      return this.name;
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'namespaceURI', {
+                    get: function () {
+                      return '';
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'prefix', {
+                    get: function () {
+                      return '';
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'localName', {
+                    get: function () {
+                      return this.name;
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'id', {
+                    get: function () {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'className', {
+                    get: function () {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'classList', {
+                    get: function () {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  Object.defineProperty(a.prototype, 'attributes', {
+                    get: function () {
+                      return (
+                        (this.attributeMap && this.attributeMap.nodes) || (this.attributeMap = new f(this.attribs)),
+                        this.attributeMap
+                      );
+                    }
+                  }),
+                  (a.prototype.clone = function () {
+                    var e,
+                      t,
+                      r,
+                      n = Object.create(this);
+                    for (t in (n.isRoot && (n.documentObject = null), (n.attribs = {}), (r = this.attribs)))
+                      s.call(r, t) && ((e = r[t]), (n.attribs[t] = e.clone()));
+                    return (
+                      (n.children = []),
+                      this.children.forEach(function (e) {
+                        e = e.clone();
+                        return (e.parent = n).children.push(e);
+                      }),
+                      n
+                    );
+                  }),
+                  (a.prototype.attribute = function (e, t) {
+                    var r, n;
+                    if ((null != e && (e = c(e)), i(e)))
+                      for (r in e) s.call(e, r) && ((n = e[r]), this.attribute(r, n));
+                    else
+                      o(t) && (t = t.apply()),
+                        this.options.keepNullAttributes && null == t
+                          ? (this.attribs[e] = new p(this, e, ''))
+                          : null != t && (this.attribs[e] = new p(this, e, t));
+                    return this;
+                  }),
+                  (a.prototype.removeAttribute = function (e) {
+                    var t, r, n;
+                    if (null == e) throw new Error('Missing attribute name. ' + this.debugInfo());
+                    if (((e = c(e)), Array.isArray(e)))
+                      for (r = 0, n = e.length; r < n; r++) (t = e[r]), delete this.attribs[t];
+                    else delete this.attribs[e];
+                    return this;
+                  }),
+                  (a.prototype.toString = function (e) {
+                    return this.options.writer.element(this, this.options.writer.filterOptions(e));
+                  }),
+                  (a.prototype.att = function (e, t) {
+                    return this.attribute(e, t);
+                  }),
+                  (a.prototype.a = function (e, t) {
+                    return this.attribute(e, t);
+                  }),
+                  (a.prototype.getAttribute = function (e) {
+                    return this.attribs.hasOwnProperty(e) ? this.attribs[e].value : null;
+                  }),
+                  (a.prototype.setAttribute = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getAttributeNode = function (e) {
+                    return this.attribs.hasOwnProperty(e) ? this.attribs[e] : null;
+                  }),
+                  (a.prototype.setAttributeNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.removeAttributeNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getElementsByTagName = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getAttributeNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.setAttributeNS = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.removeAttributeNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getAttributeNodeNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.setAttributeNodeNS = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getElementsByTagNameNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.hasAttribute = function (e) {
+                    return this.attribs.hasOwnProperty(e);
+                  }),
+                  (a.prototype.hasAttributeNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.setIdAttribute = function (e, t) {
+                    return this.attribs.hasOwnProperty(e) ? this.attribs[e].isId : t;
+                  }),
+                  (a.prototype.setIdAttributeNS = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.setIdAttributeNode = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getElementsByTagName = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getElementsByTagNameNS = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.getElementsByClassName = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (a.prototype.isEqualNode = function (e) {
+                    var t, r, n;
+                    if (!a.__super__.isEqualNode.apply(this, arguments).isEqualNode(e)) return !1;
+                    if (e.namespaceURI !== this.namespaceURI) return !1;
+                    if (e.prefix !== this.prefix) return !1;
+                    if (e.localName !== this.localName) return !1;
+                    if (e.attribs.length !== this.attribs.length) return !1;
+                    for (t = r = 0, n = this.attribs.length - 1; 0 <= n ? r <= n : n <= r; t = 0 <= n ? ++r : --r)
+                      if (!this.attribs[t].isEqualNode(e.attribs[t])) return !1;
+                    return !0;
+                  }),
+                  a
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './Utility': 403, './XMLAttribute': 405, './XMLNamedNodeMap': 423, './XMLNode': 424 }
+        ],
+        423: [
+          function (e, t, r) {
+            !function () {
+              function e(e) {
+                this.nodes = e;
+              }
+              t.exports =
+                (Object.defineProperty(e.prototype, 'length', {
+                  get: function () {
+                    return Object.keys(this.nodes).length || 0;
+                  }
+                }),
+                (e.prototype.clone = function () {
+                  return (this.nodes = null);
+                }),
+                (e.prototype.getNamedItem = function (e) {
+                  return this.nodes[e];
+                }),
+                (e.prototype.setNamedItem = function (e) {
+                  var t = this.nodes[e.nodeName];
+                  return (this.nodes[e.nodeName] = e), t || null;
+                }),
+                (e.prototype.removeNamedItem = function (e) {
+                  var t = this.nodes[e];
+                  return delete this.nodes[e], t || null;
+                }),
+                (e.prototype.item = function (e) {
+                  return this.nodes[Object.keys(this.nodes)[e]] || null;
+                }),
+                (e.prototype.getNamedItemNS = function (e, t) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                (e.prototype.setNamedItemNS = function (e) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                (e.prototype.removeNamedItemNS = function (e, t) {
+                  throw new Error('This DOM method is not implemented.');
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        424: [
+          function (v, j, e) {
+            !function () {
+              var r,
+                p,
+                t,
+                n,
+                s,
+                f,
+                i,
+                o,
+                a,
+                c,
+                l,
+                u,
+                d,
+                h,
+                m,
+                y,
+                e,
+                b = {}.hasOwnProperty;
+              function g(e) {
+                (this.parent = e),
+                  this.parent && ((this.options = this.parent.options), (this.stringify = this.parent.stringify)),
+                  (this.value = null),
+                  (this.children = []),
+                  (this.baseURI = null),
+                  o ||
+                    ((o = v('./XMLElement')),
+                    (t = v('./XMLCData')),
+                    (n = v('./XMLComment')),
+                    (s = v('./XMLDeclaration')),
+                    (f = v('./XMLDocType')),
+                    (l = v('./XMLRaw')),
+                    (u = v('./XMLText')),
+                    (c = v('./XMLProcessingInstruction')),
+                    (i = v('./XMLDummy')),
+                    (p = v('./NodeType')),
+                    (a = v('./XMLNodeList')),
+                    v('./XMLNamedNodeMap'),
+                    (r = v('./DocumentPosition')));
+              }
+              (e = v('./Utility')),
+                (y = e.isObject),
+                (m = e.isFunction),
+                (h = e.isEmpty),
+                (d = e.getValue),
+                (r = a = p = i = c = u = l = f = s = n = t = o = null),
+                (j.exports =
+                  (Object.defineProperty(g.prototype, 'nodeName', {
+                    get: function () {
+                      return this.name;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'nodeType', {
+                    get: function () {
+                      return this.type;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'nodeValue', {
+                    get: function () {
+                      return this.value;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'parentNode', {
+                    get: function () {
+                      return this.parent;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'childNodes', {
+                    get: function () {
+                      return (
+                        (this.childNodeList && this.childNodeList.nodes) || (this.childNodeList = new a(this.children)),
+                        this.childNodeList
+                      );
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'firstChild', {
+                    get: function () {
+                      return this.children[0] || null;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'lastChild', {
+                    get: function () {
+                      return this.children[this.children.length - 1] || null;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'previousSibling', {
+                    get: function () {
+                      var e = this.parent.children.indexOf(this);
+                      return this.parent.children[e - 1] || null;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'nextSibling', {
+                    get: function () {
+                      var e = this.parent.children.indexOf(this);
+                      return this.parent.children[e + 1] || null;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'ownerDocument', {
+                    get: function () {
+                      return this.document() || null;
+                    }
+                  }),
+                  Object.defineProperty(g.prototype, 'textContent', {
+                    get: function () {
+                      var e, t, r, n, s;
+                      if (this.nodeType !== p.Element && this.nodeType !== p.DocumentFragment) return null;
+                      for (s = '', t = 0, r = (n = this.children).length; t < r; t++)
+                        (e = n[t]).textContent && (s += e.textContent);
+                      return s;
+                    },
+                    set: function (e) {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  (g.prototype.setParent = function (e) {
+                    var t, r, n, s, i;
+                    for (
+                      (this.parent = e) && ((this.options = e.options), (this.stringify = e.stringify)),
+                        i = [],
+                        r = 0,
+                        n = (s = this.children).length;
+                      r < n;
+                      r++
+                    )
+                      (t = s[r]), i.push(t.setParent(this));
+                    return i;
+                  }),
+                  (g.prototype.element = function (e, t, r) {
+                    var n,
+                      s,
+                      i,
+                      o,
+                      a,
+                      c,
+                      l,
+                      u,
+                      p,
+                      f = null;
+                    if (
+                      (null === t && null == r && ((t = (u = [{}, null])[0]), (r = u[1])),
+                      (t = d((t = null == t ? {} : t))),
+                      y(t) || ((r = (u = [t, r])[0]), (t = u[1])),
+                      null != e && (e = d(e)),
+                      Array.isArray(e))
+                    )
+                      for (i = 0, c = e.length; i < c; i++) (s = e[i]), (f = this.element(s));
+                    else if (m(e)) f = this.element(e.apply());
+                    else if (y(e)) {
+                      for (a in e)
+                        if (b.call(e, a))
+                          if (
+                            ((p = e[a]),
+                            m(p) && (p = p.apply()),
+                            !this.options.ignoreDecorators &&
+                              this.stringify.convertAttKey &&
+                              0 === a.indexOf(this.stringify.convertAttKey))
+                          )
+                            f = this.attribute(a.substr(this.stringify.convertAttKey.length), p);
+                          else if (!this.options.separateArrayItems && Array.isArray(p) && h(p)) f = this.dummy();
+                          else if (y(p) && h(p)) f = this.element(a);
+                          else if (this.options.keepNullNodes || null != p)
+                            if (!this.options.separateArrayItems && Array.isArray(p))
+                              for (o = 0, l = p.length; o < l; o++)
+                                (s = p[o]), ((n = {})[a] = s), (f = this.element(n));
+                            else
+                              y(p)
+                                ? !this.options.ignoreDecorators &&
+                                  this.stringify.convertTextKey &&
+                                  0 === a.indexOf(this.stringify.convertTextKey)
+                                  ? (f = this.element(p))
+                                  : (f = this.element(a)).element(p)
+                                : (f = this.element(a, p));
+                          else f = this.dummy();
+                    } else
+                      f =
+                        this.options.keepNullNodes || null !== r
+                          ? !this.options.ignoreDecorators &&
+                            this.stringify.convertTextKey &&
+                            0 === e.indexOf(this.stringify.convertTextKey)
+                            ? this.text(r)
+                            : !this.options.ignoreDecorators &&
+                              this.stringify.convertCDataKey &&
+                              0 === e.indexOf(this.stringify.convertCDataKey)
+                            ? this.cdata(r)
+                            : !this.options.ignoreDecorators &&
+                              this.stringify.convertCommentKey &&
+                              0 === e.indexOf(this.stringify.convertCommentKey)
+                            ? this.comment(r)
+                            : !this.options.ignoreDecorators &&
+                              this.stringify.convertRawKey &&
+                              0 === e.indexOf(this.stringify.convertRawKey)
+                            ? this.raw(r)
+                            : !this.options.ignoreDecorators &&
+                              this.stringify.convertPIKey &&
+                              0 === e.indexOf(this.stringify.convertPIKey)
+                            ? this.instruction(e.substr(this.stringify.convertPIKey.length), r)
+                            : this.node(e, t, r)
+                          : this.dummy();
+                    if (null == f)
+                      throw new Error('Could not create any elements with: ' + e + '. ' + this.debugInfo());
+                    return f;
+                  }),
+                  (g.prototype.insertBefore = function (e, t, r) {
+                    var n, s, i, o;
+                    if (null != e && e.type)
+                      return (
+                        (i = t),
+                        (s = e).setParent(this),
+                        i
+                          ? ((n = children.indexOf(i)),
+                            (o = children.splice(n)),
+                            children.push(s),
+                            Array.prototype.push.apply(children, o))
+                          : children.push(s),
+                        s
+                      );
+                    if (this.isRoot) throw new Error('Cannot insert elements at root level. ' + this.debugInfo(e));
+                    return (
+                      (n = this.parent.children.indexOf(this)),
+                      (o = this.parent.children.splice(n)),
+                      (i = this.parent.element(e, t, r)),
+                      Array.prototype.push.apply(this.parent.children, o),
+                      i
+                    );
+                  }),
+                  (g.prototype.insertAfter = function (e, t, r) {
+                    var n;
+                    if (this.isRoot) throw new Error('Cannot insert elements at root level. ' + this.debugInfo(e));
+                    return (
+                      (n = this.parent.children.indexOf(this)),
+                      (n = this.parent.children.splice(n + 1)),
+                      (e = this.parent.element(e, t, r)),
+                      Array.prototype.push.apply(this.parent.children, n),
+                      e
+                    );
+                  }),
+                  (g.prototype.remove = function () {
+                    var e;
+                    if (this.isRoot) throw new Error('Cannot remove the root element. ' + this.debugInfo());
+                    return (
+                      (e = this.parent.children.indexOf(this)),
+                      [].splice.apply(this.parent.children, [e, e - e + 1].concat([])),
+                      this.parent
+                    );
+                  }),
+                  (g.prototype.node = function (e, t, r) {
+                    var n;
+                    return (
+                      null != e && (e = d(e)),
+                      (t = d((t = t || {}))),
+                      y(t) || ((r = (n = [t, r])[0]), (t = n[1])),
+                      (n = new o(this, e, t)),
+                      null != r && n.text(r),
+                      this.children.push(n),
+                      n
+                    );
+                  }),
+                  (g.prototype.text = function (e) {
+                    return y(e) && this.element(e), (e = new u(this, e)), this.children.push(e), this;
+                  }),
+                  (g.prototype.cdata = function (e) {
+                    e = new t(this, e);
+                    return this.children.push(e), this;
+                  }),
+                  (g.prototype.comment = function (e) {
+                    e = new n(this, e);
+                    return this.children.push(e), this;
+                  }),
+                  (g.prototype.commentBefore = function (e) {
+                    var t = this.parent.children.indexOf(this),
+                      t = this.parent.children.splice(t);
+                    this.parent.comment(e);
+                    return Array.prototype.push.apply(this.parent.children, t), this;
+                  }),
+                  (g.prototype.commentAfter = function (e) {
+                    var t = this.parent.children.indexOf(this),
+                      t = this.parent.children.splice(t + 1);
+                    this.parent.comment(e);
+                    return Array.prototype.push.apply(this.parent.children, t), this;
+                  }),
+                  (g.prototype.raw = function (e) {
+                    e = new l(this, e);
+                    return this.children.push(e), this;
+                  }),
+                  (g.prototype.dummy = function () {
+                    return new i(this);
+                  }),
+                  (g.prototype.instruction = function (e, t) {
+                    var r, n, s, i;
+                    if ((null != e && (e = d(e)), null != t && (t = d(t)), Array.isArray(e)))
+                      for (s = 0, i = e.length; s < i; s++) (r = e[s]), this.instruction(r);
+                    else if (y(e)) for (r in e) b.call(e, r) && ((n = e[r]), this.instruction(r, n));
+                    else m(t) && (t = t.apply()), (t = new c(this, e, t)), this.children.push(t);
+                    return this;
+                  }),
+                  (g.prototype.instructionBefore = function (e, t) {
+                    var r = this.parent.children.indexOf(this),
+                      r = this.parent.children.splice(r);
+                    this.parent.instruction(e, t);
+                    return Array.prototype.push.apply(this.parent.children, r), this;
+                  }),
+                  (g.prototype.instructionAfter = function (e, t) {
+                    var r = this.parent.children.indexOf(this),
+                      r = this.parent.children.splice(r + 1);
+                    this.parent.instruction(e, t);
+                    return Array.prototype.push.apply(this.parent.children, r), this;
+                  }),
+                  (g.prototype.declaration = function (e, t, r) {
+                    var n = this.document(),
+                      e = new s(n, e, t, r);
+                    return (
+                      0 !== n.children.length && n.children[0].type === p.Declaration
+                        ? (n.children[0] = e)
+                        : n.children.unshift(e),
+                      n.root() || n
+                    );
+                  }),
+                  (g.prototype.dtd = function (e, t) {
+                    for (
+                      var r,
+                        n,
+                        s,
+                        i,
+                        o = this.document(),
+                        a = new f(o, e, t),
+                        c = o.children,
+                        l = (r = 0),
+                        u = c.length;
+                      r < u;
+                      l = ++r
+                    )
+                      if (c[l].type === p.DocType) return (o.children[l] = a);
+                    for (l = n = 0, s = (i = o.children).length; n < s; l = ++n)
+                      if (i[l].isRoot) return o.children.splice(l, 0, a), a;
+                    return o.children.push(a), a;
+                  }),
+                  (g.prototype.up = function () {
+                    if (this.isRoot)
+                      throw new Error('The root node has no parent. Use doc() if you need to get the document object.');
+                    return this.parent;
+                  }),
+                  (g.prototype.root = function () {
+                    for (var e = this; e; ) {
+                      if (e.type === p.Document) return e.rootObject;
+                      if (e.isRoot) return e;
+                      e = e.parent;
+                    }
+                  }),
+                  (g.prototype.document = function () {
+                    for (var e = this; e; ) {
+                      if (e.type === p.Document) return e;
+                      e = e.parent;
+                    }
+                  }),
+                  (g.prototype.end = function (e) {
+                    return this.document().end(e);
+                  }),
+                  (g.prototype.prev = function () {
+                    var e = this.parent.children.indexOf(this);
+                    if (e < 1) throw new Error('Already at the first node. ' + this.debugInfo());
+                    return this.parent.children[e - 1];
+                  }),
+                  (g.prototype.next = function () {
+                    var e = this.parent.children.indexOf(this);
+                    if (-1 === e || e === this.parent.children.length - 1)
+                      throw new Error('Already at the last node. ' + this.debugInfo());
+                    return this.parent.children[e + 1];
+                  }),
+                  (g.prototype.importDocument = function (e) {
+                    e = e.root().clone();
+                    return (e.parent = this), (e.isRoot = !1), this.children.push(e), this;
+                  }),
+                  (g.prototype.debugInfo = function (e) {
+                    var t;
+                    return null != (e = e || this.name) || (null != (t = this.parent) && t.name)
+                      ? null == e
+                        ? 'parent: <' + this.parent.name + '>'
+                        : null != (t = this.parent) && t.name
+                        ? 'node: <' + e + '>, parent: <' + this.parent.name + '>'
+                        : 'node: <' + e + '>'
+                      : '';
+                  }),
+                  (g.prototype.ele = function (e, t, r) {
+                    return this.element(e, t, r);
+                  }),
+                  (g.prototype.nod = function (e, t, r) {
+                    return this.node(e, t, r);
+                  }),
+                  (g.prototype.txt = function (e) {
+                    return this.text(e);
+                  }),
+                  (g.prototype.dat = function (e) {
+                    return this.cdata(e);
+                  }),
+                  (g.prototype.com = function (e) {
+                    return this.comment(e);
+                  }),
+                  (g.prototype.ins = function (e, t) {
+                    return this.instruction(e, t);
+                  }),
+                  (g.prototype.doc = function () {
+                    return this.document();
+                  }),
+                  (g.prototype.dec = function (e, t, r) {
+                    return this.declaration(e, t, r);
+                  }),
+                  (g.prototype.e = function (e, t, r) {
+                    return this.element(e, t, r);
+                  }),
+                  (g.prototype.n = function (e, t, r) {
+                    return this.node(e, t, r);
+                  }),
+                  (g.prototype.t = function (e) {
+                    return this.text(e);
+                  }),
+                  (g.prototype.d = function (e) {
+                    return this.cdata(e);
+                  }),
+                  (g.prototype.c = function (e) {
+                    return this.comment(e);
+                  }),
+                  (g.prototype.r = function (e) {
+                    return this.raw(e);
+                  }),
+                  (g.prototype.i = function (e, t) {
+                    return this.instruction(e, t);
+                  }),
+                  (g.prototype.u = function () {
+                    return this.up();
+                  }),
+                  (g.prototype.importXMLBuilder = function (e) {
+                    return this.importDocument(e);
+                  }),
+                  (g.prototype.replaceChild = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.removeChild = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.appendChild = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.hasChildNodes = function () {
+                    return 0 !== this.children.length;
+                  }),
+                  (g.prototype.cloneNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.normalize = function () {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.isSupported = function (e, t) {
+                    return !0;
+                  }),
+                  (g.prototype.hasAttributes = function () {
+                    return 0 !== this.attribs.length;
+                  }),
+                  (g.prototype.compareDocumentPosition = function (e) {
+                    var t;
+                    return this === e
+                      ? 0
+                      : this.document() !== e.document()
+                      ? ((t = r.Disconnected | r.ImplementationSpecific),
+                        Math.random() < 0.5 ? (t |= r.Preceding) : (t |= r.Following),
+                        t)
+                      : this.isAncestor(e)
+                      ? r.Contains | r.Preceding
+                      : this.isDescendant(e)
+                      ? r.Contains | r.Following
+                      : this.isPreceding(e)
+                      ? r.Preceding
+                      : r.Following;
+                  }),
+                  (g.prototype.isSameNode = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.lookupPrefix = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.isDefaultNamespace = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.lookupNamespaceURI = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.isEqualNode = function (e) {
+                    var t, r, n;
+                    if (e.nodeType !== this.nodeType) return !1;
+                    if (e.children.length !== this.children.length) return !1;
+                    for (t = r = 0, n = this.children.length - 1; 0 <= n ? r <= n : n <= r; t = 0 <= n ? ++r : --r)
+                      if (!this.children[t].isEqualNode(e.children[t])) return !1;
+                    return !0;
+                  }),
+                  (g.prototype.getFeature = function (e, t) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.setUserData = function (e, t, r) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.getUserData = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (g.prototype.contains = function (e) {
+                    return !!e && (e === this || this.isDescendant(e));
+                  }),
+                  (g.prototype.isDescendant = function (e) {
+                    for (var t, r = this.children, n = 0, s = r.length; n < s; n++) {
+                      if (e === (t = r[n])) return !0;
+                      if (t.isDescendant(e)) return !0;
+                    }
+                    return !1;
+                  }),
+                  (g.prototype.isAncestor = function (e) {
+                    return e.isDescendant(this);
+                  }),
+                  (g.prototype.isPreceding = function (e) {
+                    var e = this.treePosition(e),
+                      t = this.treePosition(this);
+                    return -1 !== e && -1 !== t && e < t;
+                  }),
+                  (g.prototype.isFollowing = function (e) {
+                    var e = this.treePosition(e),
+                      t = this.treePosition(this);
+                    return -1 !== e && -1 !== t && t < e;
+                  }),
+                  (g.prototype.treePosition = function (t) {
+                    var r = 0,
+                      n = !1;
+                    return (
+                      this.foreachTreeNode(this.document(), function (e) {
+                        if ((r++, !n && e === t)) return (n = !0);
+                      }),
+                      n ? r : -1
+                    );
+                  }),
+                  (g.prototype.foreachTreeNode = function (e, t) {
+                    for (var r, n, s, i = 0, o = (n = (e = e || this.document()).children).length; i < o; i++) {
+                      if ((s = t((r = n[i])))) return s;
+                      if ((s = this.foreachTreeNode(r, t))) return s;
+                    }
+                  }),
+                  g));
+            }.call(this);
+          },
+          {
+            './DocumentPosition': 401,
+            './NodeType': 402,
+            './Utility': 403,
+            './XMLCData': 406,
+            './XMLComment': 408,
+            './XMLDeclaration': 417,
+            './XMLDocType': 418,
+            './XMLDummy': 421,
+            './XMLElement': 422,
+            './XMLNamedNodeMap': 423,
+            './XMLNodeList': 425,
+            './XMLProcessingInstruction': 426,
+            './XMLRaw': 427,
+            './XMLText': 431
+          }
+        ],
+        425: [
+          function (e, t, r) {
+            !function () {
+              function e(e) {
+                this.nodes = e;
+              }
+              t.exports =
+                (Object.defineProperty(e.prototype, 'length', {
+                  get: function () {
+                    return this.nodes.length || 0;
+                  }
+                }),
+                (e.prototype.clone = function () {
+                  return (this.nodes = null);
+                }),
+                (e.prototype.item = function (e) {
+                  return this.nodes[e] || null;
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        426: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./NodeType'),
+                a = e('./XMLCharacterData');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t, r) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing instruction target. ' + this.debugInfo());
+                  (this.type = o.ProcessingInstruction),
+                    (this.target = this.stringify.insTarget(t)),
+                    (this.name = this.target),
+                    r && (this.value = this.stringify.insValue(r));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.processingInstruction(this, this.options.writer.filterOptions(e));
+                  }),
+                  (s.prototype.isEqualNode = function (e) {
+                    return !!s.__super__.isEqualNode.apply(this, arguments).isEqualNode(e) && e.target === this.target;
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLCharacterData': 407 }
+        ],
+        427: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./NodeType'),
+                a = e('./XMLNode');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing raw text. ' + this.debugInfo());
+                  (this.type = o.Raw), (this.value = this.stringify.raw(t));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.raw(this, this.options.writer.filterOptions(e));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLNode': 424 }
+        ],
+        428: [
+          function (e, t, r) {
+            !function () {
+              var f = {}.hasOwnProperty,
+                d = e('./NodeType'),
+                i = e('./XMLWriterBase'),
+                h = e('./WriterState');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = i;
+                for (e in r) f.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t) {
+                  (this.stream = e), s.__super__.constructor.call(this, t);
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.endline = function (e, t, r) {
+                    return e.isLastRootNode && t.state === h.CloseTag ? '' : s.__super__.endline.call(this, e, t, r);
+                  }),
+                  (s.prototype.document = function (e, t) {
+                    for (var r, n, s, i, o, a, c = e.children, l = (n = 0), u = c.length; n < u; l = ++n)
+                      (r = c[l]).isLastRootNode = l === e.children.length - 1;
+                    for (t = this.filterOptions(t), a = [], s = 0, i = (o = e.children).length; s < i; s++)
+                      (r = o[s]), a.push(this.writeChildNode(r, t, 0));
+                    return a;
+                  }),
+                  (s.prototype.attribute = function (e, t, r) {
+                    return this.stream.write(s.__super__.attribute.call(this, e, t, r));
+                  }),
+                  (s.prototype.cdata = function (e, t, r) {
+                    return this.stream.write(s.__super__.cdata.call(this, e, t, r));
+                  }),
+                  (s.prototype.comment = function (e, t, r) {
+                    return this.stream.write(s.__super__.comment.call(this, e, t, r));
+                  }),
+                  (s.prototype.declaration = function (e, t, r) {
+                    return this.stream.write(s.__super__.declaration.call(this, e, t, r));
+                  }),
+                  (s.prototype.docType = function (e, t, r) {
+                    var n, s, i, o;
+                    if (
+                      (this.openNode(e, t, (r = r || 0)),
+                      (t.state = h.OpenTag),
+                      this.stream.write(this.indent(e, t, r)),
+                      this.stream.write('<!DOCTYPE ' + e.root().name),
+                      e.pubID && e.sysID
+                        ? this.stream.write(' PUBLIC "' + e.pubID + '" "' + e.sysID + '"')
+                        : e.sysID && this.stream.write(' SYSTEM "' + e.sysID + '"'),
+                      0 < e.children.length)
+                    ) {
+                      for (
+                        this.stream.write(' ['),
+                          this.stream.write(this.endline(e, t, r)),
+                          t.state = h.InsideTag,
+                          s = 0,
+                          i = (o = e.children).length;
+                        s < i;
+                        s++
+                      )
+                        (n = o[s]), this.writeChildNode(n, t, r + 1);
+                      (t.state = h.CloseTag), this.stream.write(']');
+                    }
+                    return (
+                      (t.state = h.CloseTag),
+                      this.stream.write(t.spaceBeforeSlash + '>'),
+                      this.stream.write(this.endline(e, t, r)),
+                      (t.state = h.None),
+                      this.closeNode(e, t, r)
+                    );
+                  }),
+                  (s.prototype.element = function (e, t, r) {
+                    var n, s, i, o, a, c, l, u, p;
+                    for (l in (this.openNode(e, t, (r = r || 0)),
+                    (t.state = h.OpenTag),
+                    this.stream.write(this.indent(e, t, r) + '<' + e.name),
+                    (u = e.attribs)))
+                      f.call(u, l) && ((n = u[l]), this.attribute(n, t, r));
+                    if (
+                      ((o = 0 === (i = e.children.length) ? null : e.children[0]),
+                      0 === i ||
+                        e.children.every(function (e) {
+                          return (e.type === d.Text || e.type === d.Raw) && '' === e.value;
+                        }))
+                    )
+                      t.allowEmpty
+                        ? (this.stream.write('>'), (t.state = h.CloseTag), this.stream.write('</' + e.name + '>'))
+                        : ((t.state = h.CloseTag), this.stream.write(t.spaceBeforeSlash + '/>'));
+                    else if (!t.pretty || 1 !== i || (o.type !== d.Text && o.type !== d.Raw) || null == o.value) {
+                      for (
+                        this.stream.write('>' + this.endline(e, t, r)),
+                          t.state = h.InsideTag,
+                          a = 0,
+                          c = (p = e.children).length;
+                        a < c;
+                        a++
+                      )
+                        (s = p[a]), this.writeChildNode(s, t, r + 1);
+                      (t.state = h.CloseTag), this.stream.write(this.indent(e, t, r) + '</' + e.name + '>');
+                    } else
+                      this.stream.write('>'),
+                        (t.state = h.InsideTag),
+                        t.suppressPrettyCount++,
+                        this.writeChildNode(o, t, r + 1),
+                        t.suppressPrettyCount--,
+                        (t.state = h.CloseTag),
+                        this.stream.write('</' + e.name + '>');
+                    return this.stream.write(this.endline(e, t, r)), (t.state = h.None), this.closeNode(e, t, r);
+                  }),
+                  (s.prototype.processingInstruction = function (e, t, r) {
+                    return this.stream.write(s.__super__.processingInstruction.call(this, e, t, r));
+                  }),
+                  (s.prototype.raw = function (e, t, r) {
+                    return this.stream.write(s.__super__.raw.call(this, e, t, r));
+                  }),
+                  (s.prototype.text = function (e, t, r) {
+                    return this.stream.write(s.__super__.text.call(this, e, t, r));
+                  }),
+                  (s.prototype.dtdAttList = function (e, t, r) {
+                    return this.stream.write(s.__super__.dtdAttList.call(this, e, t, r));
+                  }),
+                  (s.prototype.dtdElement = function (e, t, r) {
+                    return this.stream.write(s.__super__.dtdElement.call(this, e, t, r));
+                  }),
+                  (s.prototype.dtdEntity = function (e, t, r) {
+                    return this.stream.write(s.__super__.dtdEntity.call(this, e, t, r));
+                  }),
+                  (s.prototype.dtdNotation = function (e, t, r) {
+                    return this.stream.write(s.__super__.dtdNotation.call(this, e, t, r));
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './WriterState': 404, './XMLWriterBase': 432 }
+        ],
+        429: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./XMLWriterBase');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = o;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e) {
+                  s.__super__.constructor.call(this, e);
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  (s.prototype.document = function (e, t) {
+                    var r, n, s, i, o;
+                    for (t = this.filterOptions(t), i = '', n = 0, s = (o = e.children).length; n < s; n++)
+                      (r = o[n]), (i += this.writeChildNode(r, t, 0));
+                    return (i =
+                      t.pretty && i.slice(-t.newline.length) === t.newline ? i.slice(0, -t.newline.length) : i);
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './XMLWriterBase': 432 }
+        ],
+        430: [
+          function (e, t, r) {
+            !function () {
+              function s(e, t) {
+                return function () {
+                  return e.apply(t, arguments);
+                };
+              }
+              var i = {}.hasOwnProperty;
+              function e(e) {
+                var t, r, n;
+                for (t in ((this.assertLegalName = s(this.assertLegalName, this)),
+                (this.assertLegalChar = s(this.assertLegalChar, this)),
+                (this.options = e = e || {}),
+                this.options.version || (this.options.version = '1.0'),
+                (r = e.stringify || {})))
+                  i.call(r, t) && ((n = r[t]), (this[t] = n));
+              }
+              t.exports =
+                ((e.prototype.name = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalName('' + e || '');
+                }),
+                (e.prototype.text = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar(this.textEscape('' + e || ''));
+                }),
+                (e.prototype.cdata = function (e) {
+                  return this.options.noValidation
+                    ? e
+                    : ((e = (e = '' + e || '').replace(']]>', ']]]]><![CDATA[>')), this.assertLegalChar(e));
+                }),
+                (e.prototype.comment = function (e) {
+                  if (this.options.noValidation) return e;
+                  if ((e = '' + e || '').match(/--/)) throw new Error('Comment text cannot contain double-hypen: ' + e);
+                  return this.assertLegalChar(e);
+                }),
+                (e.prototype.raw = function (e) {
+                  return this.options.noValidation ? e : '' + e || '';
+                }),
+                (e.prototype.attValue = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar(this.attEscape((e = '' + e || '')));
+                }),
+                (e.prototype.insTarget = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.insValue = function (e) {
+                  if (this.options.noValidation) return e;
+                  if ((e = '' + e || '').match(/\?>/)) throw new Error('Invalid processing instruction value: ' + e);
+                  return this.assertLegalChar(e);
+                }),
+                (e.prototype.xmlVersion = function (e) {
+                  if (this.options.noValidation) return e;
+                  if ((e = '' + e || '').match(/1\.[0-9]+/)) return e;
+                  throw new Error('Invalid version number: ' + e);
+                }),
+                (e.prototype.xmlEncoding = function (e) {
+                  if (this.options.noValidation) return e;
+                  if ((e = '' + e || '').match(/^[A-Za-z](?:[A-Za-z0-9._-])*$/)) return this.assertLegalChar(e);
+                  throw new Error('Invalid encoding: ' + e);
+                }),
+                (e.prototype.xmlStandalone = function (e) {
+                  return this.options.noValidation ? e : e ? 'yes' : 'no';
+                }),
+                (e.prototype.dtdPubID = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdSysID = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdElementValue = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdAttType = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdAttDefault = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdEntityValue = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.dtdNData = function (e) {
+                  return this.options.noValidation ? e : this.assertLegalChar('' + e || '');
+                }),
+                (e.prototype.convertAttKey = '@'),
+                (e.prototype.convertPIKey = '?'),
+                (e.prototype.convertTextKey = '#text'),
+                (e.prototype.convertCDataKey = '#cdata'),
+                (e.prototype.convertCommentKey = '#comment'),
+                (e.prototype.convertRawKey = '#raw'),
+                (e.prototype.assertLegalChar = function (e) {
+                  var t;
+                  if (this.options.noValidation) return e;
+                  if ('1.0' === this.options.version) {
+                    if (
+                      (t = e.match(
+                        /[\0-\x08\x0B\f\x0E-\x1F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/
+                      ))
+                    )
+                      throw new Error('Invalid character in string: ' + e + ' at index ' + t.index);
+                  } else if (
+                    '1.1' === this.options.version &&
+                    (t = e.match(
+                      /[\0\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/
+                    ))
+                  )
+                    throw new Error('Invalid character in string: ' + e + ' at index ' + t.index);
+                  return e;
+                }),
+                (e.prototype.assertLegalName = function (e) {
+                  if (this.options.noValidation) return e;
+                  if (
+                    (this.assertLegalChar(e),
+                    e.match(
+                      /^([:A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])([\x2D\.0-:A-Z_a-z\xB7\xC0-\xD6\xD8-\xF6\xF8-\u037D\u037F-\u1FFF\u200C\u200D\u203F\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])*$/
+                    ))
+                  )
+                    return e;
+                  throw new Error('Invalid character in name');
+                }),
+                (e.prototype.textEscape = function (e) {
+                  var t;
+                  return this.options.noValidation
+                    ? e
+                    : ((t = this.options.noDoubleEncoding ? /(?!&\S+;)&/g : /&/g),
+                      e.replace(t, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\r/g, '&#xD;'));
+                }),
+                (e.prototype.attEscape = function (e) {
+                  var t;
+                  return this.options.noValidation
+                    ? e
+                    : ((t = this.options.noDoubleEncoding ? /(?!&\S+;)&/g : /&/g),
+                      e
+                        .replace(t, '&amp;')
+                        .replace(/</g, '&lt;')
+                        .replace(/"/g, '&quot;')
+                        .replace(/\t/g, '&#x9;')
+                        .replace(/\n/g, '&#xA;')
+                        .replace(/\r/g, '&#xD;'));
+                }),
+                e);
+            }.call(this);
+          },
+          {}
+        ],
+        431: [
+          function (e, t, r) {
+            !function () {
+              var i = {}.hasOwnProperty,
+                o = e('./NodeType'),
+                a = e('./XMLCharacterData');
+              t.exports = (function () {
+                var e,
+                  t = s,
+                  r = a;
+                for (e in r) i.call(r, e) && (t[e] = r[e]);
+                function n() {
+                  this.constructor = t;
+                }
+                function s(e, t) {
+                  if ((s.__super__.constructor.call(this, e), null == t))
+                    throw new Error('Missing element text. ' + this.debugInfo());
+                  (this.name = '#text'), (this.type = o.Text), (this.value = this.stringify.text(t));
+                }
+                return (
+                  (n.prototype = r.prototype),
+                  (t.prototype = new n()),
+                  (t.__super__ = r.prototype),
+                  Object.defineProperty(s.prototype, 'isElementContentWhitespace', {
+                    get: function () {
+                      throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                    }
+                  }),
+                  Object.defineProperty(s.prototype, 'wholeText', {
+                    get: function () {
+                      for (var e, t = '', r = this.previousSibling; r; ) (t = r.data + t), (r = r.previousSibling);
+                      for (t += this.data, e = this.nextSibling; e; ) (t += e.data), (e = e.nextSibling);
+                      return t;
+                    }
+                  }),
+                  (s.prototype.clone = function () {
+                    return Object.create(this);
+                  }),
+                  (s.prototype.toString = function (e) {
+                    return this.options.writer.text(this, this.options.writer.filterOptions(e));
+                  }),
+                  (s.prototype.splitText = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  (s.prototype.replaceWholeText = function (e) {
+                    throw new Error('This DOM method is not implemented.' + this.debugInfo());
+                  }),
+                  s
+                );
+              })();
+            }.call(this);
+          },
+          { './NodeType': 402, './XMLCharacterData': 407 }
+        ],
+        432: [
+          function (t, r, e) {
+            !function () {
+              var b,
+                g,
+                n,
+                v = {}.hasOwnProperty;
+              function e(e) {
+                var t, r, n;
+                for (t in (r = (this.options = e = e || {}).writer || {}))
+                  v.call(r, t) && ((n = r[t]), (this['_' + t] = this[t]), (this[t] = n));
+              }
+              (n = t('./Utility').assign),
+                (b = t('./NodeType')),
+                t('./XMLDeclaration'),
+                t('./XMLDocType'),
+                t('./XMLCData'),
+                t('./XMLComment'),
+                t('./XMLElement'),
+                t('./XMLRaw'),
+                t('./XMLText'),
+                t('./XMLProcessingInstruction'),
+                t('./XMLDummy'),
+                t('./XMLDTDAttList'),
+                t('./XMLDTDElement'),
+                t('./XMLDTDEntity'),
+                t('./XMLDTDNotation'),
+                (g = t('./WriterState')),
+                (r.exports =
+                  ((e.prototype.filterOptions = function (e) {
+                    var t, r;
+                    return (
+                      (e = n({}, this.options, (e = e || {}))),
+                      ((t = { writer: this }).pretty = e.pretty || !1),
+                      (t.allowEmpty = e.allowEmpty || !1),
+                      (t.indent = null != (r = e.indent) ? r : '  '),
+                      (t.newline = null != (r = e.newline) ? r : '\n'),
+                      (t.offset = null != (r = e.offset) ? r : 0),
+                      (t.dontPrettyTextNodes =
+                        null != (r = null != (r = e.dontPrettyTextNodes) ? r : e.dontprettytextnodes) ? r : 0),
+                      (t.spaceBeforeSlash =
+                        null != (r = null != (r = e.spaceBeforeSlash) ? r : e.spacebeforeslash) ? r : ''),
+                      !0 === t.spaceBeforeSlash && (t.spaceBeforeSlash = ' '),
+                      (t.suppressPrettyCount = 0),
+                      (t.user = {}),
+                      (t.state = g.None),
+                      t
+                    );
+                  }),
+                  (e.prototype.indent = function (e, t, r) {
+                    return t.pretty && !t.suppressPrettyCount && t.pretty && 0 < (r = (r || 0) + t.offset + 1)
+                      ? new Array(r).join(t.indent)
+                      : '';
+                  }),
+                  (e.prototype.endline = function (e, t, r) {
+                    return !t.pretty || t.suppressPrettyCount ? '' : t.newline;
+                  }),
+                  (e.prototype.attribute = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openAttribute(e, t, r),
+                      (n = ' ' + e.name + '="' + e.value + '"'),
+                      this.closeAttribute(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.cdata = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<![CDATA['),
+                      (t.state = g.InsideTag),
+                      (n += e.value),
+                      (t.state = g.CloseTag),
+                      (n += ']]>' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.comment = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '\x3c!-- '),
+                      (t.state = g.InsideTag),
+                      (n += e.value),
+                      (t.state = g.CloseTag),
+                      (n += ' --\x3e' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.declaration = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<?xml'),
+                      (t.state = g.InsideTag),
+                      (n += ' version="' + e.version + '"'),
+                      null != e.encoding && (n += ' encoding="' + e.encoding + '"'),
+                      null != e.standalone && (n += ' standalone="' + e.standalone + '"'),
+                      (t.state = g.CloseTag),
+                      (n = (n += t.spaceBeforeSlash + '?>') + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.docType = function (e, t, r) {
+                    var n, s, i, o, a;
+                    if (
+                      (this.openNode(e, t, (r = r || 0)),
+                      (t.state = g.OpenTag),
+                      (o = this.indent(e, t, r)),
+                      (o += '<!DOCTYPE ' + e.root().name),
+                      e.pubID && e.sysID
+                        ? (o += ' PUBLIC "' + e.pubID + '" "' + e.sysID + '"')
+                        : e.sysID && (o += ' SYSTEM "' + e.sysID + '"'),
+                      0 < e.children.length)
+                    ) {
+                      for (
+                        o = (o += ' [') + this.endline(e, t, r),
+                          t.state = g.InsideTag,
+                          s = 0,
+                          i = (a = e.children).length;
+                        s < i;
+                        s++
+                      )
+                        (n = a[s]), (o += this.writeChildNode(n, t, r + 1));
+                      (t.state = g.CloseTag), (o += ']');
+                    }
+                    return (
+                      (t.state = g.CloseTag),
+                      (o = (o += t.spaceBeforeSlash + '>') + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      o
+                    );
+                  }),
+                  (e.prototype.element = function (e, t, r) {
+                    var n,
+                      s,
+                      i,
+                      o,
+                      a,
+                      c,
+                      l,
+                      u,
+                      p,
+                      f,
+                      d,
+                      h,
+                      m = !1,
+                      y = '';
+                    for (p in (this.openNode(e, t, (r = r || 0)),
+                    (t.state = g.OpenTag),
+                    (y += this.indent(e, t, r) + '<' + e.name),
+                    (f = e.attribs)))
+                      v.call(f, p) && ((n = f[p]), (y += this.attribute(n, t, r)));
+                    if (
+                      ((o = 0 === (i = e.children.length) ? null : e.children[0]),
+                      0 === i ||
+                        e.children.every(function (e) {
+                          return (e.type === b.Text || e.type === b.Raw) && '' === e.value;
+                        }))
+                    )
+                      t.allowEmpty
+                        ? ((y += '>'), (t.state = g.CloseTag), (y += '</' + e.name + '>' + this.endline(e, t, r)))
+                        : ((t.state = g.CloseTag), (y += t.spaceBeforeSlash + '/>' + this.endline(e, t, r)));
+                    else if (!t.pretty || 1 !== i || (o.type !== b.Text && o.type !== b.Raw) || null == o.value) {
+                      if (t.dontPrettyTextNodes)
+                        for (a = 0, l = (d = e.children).length; a < l; a++)
+                          if (((s = d[a]).type === b.Text || s.type === b.Raw) && null != s.value) {
+                            t.suppressPrettyCount++, (m = !0);
+                            break;
+                          }
+                      for (
+                        y += '>' + this.endline(e, t, r), t.state = g.InsideTag, c = 0, u = (h = e.children).length;
+                        c < u;
+                        c++
+                      )
+                        (s = h[c]), (y += this.writeChildNode(s, t, r + 1));
+                      (t.state = g.CloseTag),
+                        (y += this.indent(e, t, r) + '</' + e.name + '>'),
+                        m && t.suppressPrettyCount--,
+                        (y += this.endline(e, t, r)),
+                        (t.state = g.None);
+                    } else
+                      (y += '>'),
+                        (t.state = g.InsideTag),
+                        t.suppressPrettyCount++,
+                        (m = !0),
+                        (y += this.writeChildNode(o, t, r + 1)),
+                        t.suppressPrettyCount--,
+                        (m = !1),
+                        (t.state = g.CloseTag),
+                        (y += '</' + e.name + '>' + this.endline(e, t, r));
+                    return this.closeNode(e, t, r), y;
+                  }),
+                  (e.prototype.writeChildNode = function (e, t, r) {
+                    switch (e.type) {
+                      case b.CData:
+                        return this.cdata(e, t, r);
+                      case b.Comment:
+                        return this.comment(e, t, r);
+                      case b.Element:
+                        return this.element(e, t, r);
+                      case b.Raw:
+                        return this.raw(e, t, r);
+                      case b.Text:
+                        return this.text(e, t, r);
+                      case b.ProcessingInstruction:
+                        return this.processingInstruction(e, t, r);
+                      case b.Dummy:
+                        return '';
+                      case b.Declaration:
+                        return this.declaration(e, t, r);
+                      case b.DocType:
+                        return this.docType(e, t, r);
+                      case b.AttributeDeclaration:
+                        return this.dtdAttList(e, t, r);
+                      case b.ElementDeclaration:
+                        return this.dtdElement(e, t, r);
+                      case b.EntityDeclaration:
+                        return this.dtdEntity(e, t, r);
+                      case b.NotationDeclaration:
+                        return this.dtdNotation(e, t, r);
+                      default:
+                        throw new Error('Unknown XML node type: ' + e.constructor.name);
+                    }
+                  }),
+                  (e.prototype.processingInstruction = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<?'),
+                      (t.state = g.InsideTag),
+                      (n += e.target),
+                      e.value && (n += ' ' + e.value),
+                      (t.state = g.CloseTag),
+                      (n = (n += t.spaceBeforeSlash + '?>') + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.raw = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r)),
+                      (t.state = g.InsideTag),
+                      (n += e.value),
+                      (t.state = g.CloseTag),
+                      (n += this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.text = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r)),
+                      (t.state = g.InsideTag),
+                      (n += e.value),
+                      (t.state = g.CloseTag),
+                      (n += this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.dtdAttList = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<!ATTLIST'),
+                      (t.state = g.InsideTag),
+                      (n += ' ' + e.elementName + ' ' + e.attributeName + ' ' + e.attributeType),
+                      '#DEFAULT' !== e.defaultValueType && (n += ' ' + e.defaultValueType),
+                      e.defaultValue && (n += ' "' + e.defaultValue + '"'),
+                      (t.state = g.CloseTag),
+                      (n += t.spaceBeforeSlash + '>' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.dtdElement = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<!ELEMENT'),
+                      (t.state = g.InsideTag),
+                      (n += ' ' + e.name + ' ' + e.value),
+                      (t.state = g.CloseTag),
+                      (n += t.spaceBeforeSlash + '>' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.dtdEntity = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<!ENTITY'),
+                      (t.state = g.InsideTag),
+                      e.pe && (n += ' %'),
+                      (n += ' ' + e.name),
+                      e.value
+                        ? (n += ' "' + e.value + '"')
+                        : (e.pubID && e.sysID
+                            ? (n += ' PUBLIC "' + e.pubID + '" "' + e.sysID + '"')
+                            : e.sysID && (n += ' SYSTEM "' + e.sysID + '"'),
+                          e.nData && (n += ' NDATA ' + e.nData)),
+                      (t.state = g.CloseTag),
+                      (n += t.spaceBeforeSlash + '>' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.dtdNotation = function (e, t, r) {
+                    var n;
+                    return (
+                      this.openNode(e, t, r),
+                      (t.state = g.OpenTag),
+                      (n = this.indent(e, t, r) + '<!NOTATION'),
+                      (t.state = g.InsideTag),
+                      (n += ' ' + e.name),
+                      e.pubID && e.sysID
+                        ? (n += ' PUBLIC "' + e.pubID + '" "' + e.sysID + '"')
+                        : e.pubID
+                        ? (n += ' PUBLIC "' + e.pubID + '"')
+                        : e.sysID && (n += ' SYSTEM "' + e.sysID + '"'),
+                      (t.state = g.CloseTag),
+                      (n += t.spaceBeforeSlash + '>' + this.endline(e, t, r)),
+                      (t.state = g.None),
+                      this.closeNode(e, t, r),
+                      n
+                    );
+                  }),
+                  (e.prototype.openNode = function (e, t, r) {}),
+                  (e.prototype.closeNode = function (e, t, r) {}),
+                  (e.prototype.openAttribute = function (e, t, r) {}),
+                  (e.prototype.closeAttribute = function (e, t, r) {}),
+                  e));
+            }.call(this);
+          },
+          {
+            './NodeType': 402,
+            './Utility': 403,
+            './WriterState': 404,
+            './XMLCData': 406,
+            './XMLComment': 408,
+            './XMLDTDAttList': 413,
+            './XMLDTDElement': 414,
+            './XMLDTDEntity': 415,
+            './XMLDTDNotation': 416,
+            './XMLDeclaration': 417,
+            './XMLDocType': 418,
+            './XMLDummy': 421,
+            './XMLElement': 422,
+            './XMLProcessingInstruction': 426,
+            './XMLRaw': 427,
+            './XMLText': 431
+          }
+        ],
+        433: [
+          function (l, u, e) {
+            !function () {
+              var e = l('./Utility'),
+                s = e.assign,
+                i = e.isFunction,
+                e = l('./XMLDOMImplementation'),
+                o = l('./XMLDocument'),
+                a = l('./XMLDocumentCB'),
+                t = l('./XMLStringWriter'),
+                r = l('./XMLStreamWriter'),
+                n = l('./NodeType'),
+                c = l('./WriterState');
+              (u.exports.create = function (e, t, r, n) {
+                if (null == e) throw new Error('Root element needs a name.');
+                return (
+                  (n = s({}, t, r, n)),
+                  (r = (t = new o(n)).element(e)),
+                  n.headless || (t.declaration(n), (null == n.pubID && null == n.sysID) || t.dtd(n)),
+                  r
+                );
+              }),
+                (u.exports.begin = function (e, t, r) {
+                  var n;
+                  return i(e) && ((t = (n = [e, t])[0]), (r = n[1]), (e = {})), t ? new a(e, t, r) : new o(e);
+                }),
+                (u.exports.stringWriter = function (e) {
+                  return new t(e);
+                }),
+                (u.exports.streamWriter = function (e, t) {
+                  return new r(e, t);
+                }),
+                (u.exports.implementation = new e()),
+                (u.exports.nodeType = n),
+                (u.exports.writerState = c);
+            }.call(this);
+          },
+          {
+            './NodeType': 402,
+            './Utility': 403,
+            './WriterState': 404,
+            './XMLDOMImplementation': 411,
+            './XMLDocument': 419,
+            './XMLDocumentCB': 420,
+            './XMLStreamWriter': 428,
+            './XMLStringWriter': 429
+          }
+        ],
+        434: [
+          function (e, t, r) {
+            t.exports = function () {
+              for (var e = {}, t = 0; t < arguments.length; t++) {
+                var r,
+                  n = arguments[t];
+                for (r in n) s.call(n, r) && (e[r] = n[r]);
+              }
+              return e;
+            };
+            var s = Object.prototype.hasOwnProperty;
+          },
+          {}
+        ],
+        435: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.fill.js'),
+              e('core-js/modules/es.array.concat.js'),
+              e('core-js/modules/es.object.to-string.js'),
+              e('core-js/modules/es.regexp.to-string.js'),
+              e('core-js/modules/es.array.join.js'),
+              e('core-js/modules/es.array.slice.js');
+            var o = e('buffer').Buffer,
+              i = { sha1: e('./sha'), md5: e('./md5') },
+              a = 64,
+              c = o.alloc(a);
+            function n(e, r) {
+              var n = i[(e = e || 'sha1')],
+                s = [];
+              return (
+                n || l('algorithm:', e, 'is not yet supported'),
+                {
+                  update: function (e) {
+                    return o.isBuffer(e) || (e = o.from(e)), s.push(e), e.length, this;
+                  },
+                  digest: function (e) {
+                    var t = o.concat(s),
+                      t = r
+                        ? (function (e, t, r) {
+                            o.isBuffer(t) || (t = o.from(t)),
+                              o.isBuffer(r) || (r = o.from(r)),
+                              t.length > a ? (t = e(t)) : t.length < a && (t = o.concat([t, c], a));
+                            for (var n = o.alloc(a), s = o.alloc(a), i = 0; i < a; i++)
+                              (n[i] = 54 ^ t[i]), (s[i] = 92 ^ t[i]);
+                            return (r = e(o.concat([n, r]))), e(o.concat([s, r]));
+                          })(n, r, t)
+                        : n(t);
+                    return (s = null), e ? t.toString(e) : t;
+                  }
+                }
+              );
+            }
+            function l() {
+              var e = [].slice.call(arguments).join(' ');
+              throw new Error(
+                [e, 'we accept pull requests', 'http://github.com/dominictarr/crypto-browserify'].join('\n')
+              );
+            }
+            c.fill(0),
+              (r.createHash = function (e) {
+                return n(e);
+              }),
+              (r.createHmac = n),
+              (r.createCredentials = function () {
+                l('sorry,createCredentials is not implemented yet');
+              }),
+              (r.createCipher = function () {
+                l('sorry,createCipher is not implemented yet');
+              }),
+              (r.createCipheriv = function () {
+                l('sorry,createCipheriv is not implemented yet');
+              }),
+              (r.createDecipher = function () {
+                l('sorry,createDecipher is not implemented yet');
+              }),
+              (r.createDecipheriv = function () {
+                l('sorry,createDecipheriv is not implemented yet');
+              }),
+              (r.createSign = function () {
+                l('sorry,createSign is not implemented yet');
+              }),
+              (r.createVerify = function () {
+                l('sorry,createVerify is not implemented yet');
+              }),
+              (r.createDiffieHellman = function () {
+                l('sorry,createDiffieHellman is not implemented yet');
+              }),
+              (r.pbkdf2 = function () {
+                l('sorry,pbkdf2 is not implemented yet');
+              });
+          },
+          {
+            './md5': 437,
+            './sha': 438,
+            buffer: 89,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.fill.js': 270,
+            'core-js/modules/es.array.join.js': 276,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.regexp.to-string.js': 300
+          }
+        ],
+        436: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.array.fill.js'), e('core-js/modules/es.array.concat.js');
+            var c = e('buffer').Buffer,
+              l = 4,
+              u = c.alloc(l);
+            u.fill(0);
+            t.exports = {
+              hash: function (e, t, r, n) {
+                for (
+                  var s = t(
+                      (function (e, t) {
+                        e.length % l != 0 && ((r = e.length + (l - (e.length % l))), (e = c.concat([e, u], r)));
+                        for (var r, n = [], s = t ? e.readInt32BE : e.readInt32LE, i = 0; i < e.length; i += l)
+                          n.push(s.call(e, i));
+                        return n;
+                      })((e = c.isBuffer(e) ? e : c.from(e)), n),
+                      8 * e.length
+                    ),
+                    t = r,
+                    e = n,
+                    i = c.alloc(t),
+                    o = e ? i.writeInt32BE : i.writeInt32LE,
+                    a = 0;
+                  a < s.length;
+                  a++
+                )
+                  o.call(i, s[a], 4 * a, !0);
+                return i;
+              }
+            };
+          },
+          { buffer: 89, 'core-js/modules/es.array.concat.js': 269, 'core-js/modules/es.array.fill.js': 270 }
+        ],
+        437: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('./helpers');
+            function s(e, t) {
+              (e[t >> 5] |= 128 << t % 32), (e[14 + (((t + 64) >>> 9) << 4)] = t);
+              for (var r = 1732584193, n = -271733879, s = -1732584194, i = 271733878, o = 0; o < e.length; o += 16) {
+                var a = r,
+                  c = n,
+                  l = s,
+                  u = i,
+                  r = p(r, n, s, i, e[o + 0], 7, -680876936),
+                  i = p(i, r, n, s, e[o + 1], 12, -389564586),
+                  s = p(s, i, r, n, e[o + 2], 17, 606105819),
+                  n = p(n, s, i, r, e[o + 3], 22, -1044525330);
+                (r = p(r, n, s, i, e[o + 4], 7, -176418897)),
+                  (i = p(i, r, n, s, e[o + 5], 12, 1200080426)),
+                  (s = p(s, i, r, n, e[o + 6], 17, -1473231341)),
+                  (n = p(n, s, i, r, e[o + 7], 22, -45705983)),
+                  (r = p(r, n, s, i, e[o + 8], 7, 1770035416)),
+                  (i = p(i, r, n, s, e[o + 9], 12, -1958414417)),
+                  (s = p(s, i, r, n, e[o + 10], 17, -42063)),
+                  (n = p(n, s, i, r, e[o + 11], 22, -1990404162)),
+                  (r = p(r, n, s, i, e[o + 12], 7, 1804603682)),
+                  (i = p(i, r, n, s, e[o + 13], 12, -40341101)),
+                  (s = p(s, i, r, n, e[o + 14], 17, -1502002290)),
+                  (r = f(r, (n = p(n, s, i, r, e[o + 15], 22, 1236535329)), s, i, e[o + 1], 5, -165796510)),
+                  (i = f(i, r, n, s, e[o + 6], 9, -1069501632)),
+                  (s = f(s, i, r, n, e[o + 11], 14, 643717713)),
+                  (n = f(n, s, i, r, e[o + 0], 20, -373897302)),
+                  (r = f(r, n, s, i, e[o + 5], 5, -701558691)),
+                  (i = f(i, r, n, s, e[o + 10], 9, 38016083)),
+                  (s = f(s, i, r, n, e[o + 15], 14, -660478335)),
+                  (n = f(n, s, i, r, e[o + 4], 20, -405537848)),
+                  (r = f(r, n, s, i, e[o + 9], 5, 568446438)),
+                  (i = f(i, r, n, s, e[o + 14], 9, -1019803690)),
+                  (s = f(s, i, r, n, e[o + 3], 14, -187363961)),
+                  (n = f(n, s, i, r, e[o + 8], 20, 1163531501)),
+                  (r = f(r, n, s, i, e[o + 13], 5, -1444681467)),
+                  (i = f(i, r, n, s, e[o + 2], 9, -51403784)),
+                  (s = f(s, i, r, n, e[o + 7], 14, 1735328473)),
+                  (r = d(r, (n = f(n, s, i, r, e[o + 12], 20, -1926607734)), s, i, e[o + 5], 4, -378558)),
+                  (i = d(i, r, n, s, e[o + 8], 11, -2022574463)),
+                  (s = d(s, i, r, n, e[o + 11], 16, 1839030562)),
+                  (n = d(n, s, i, r, e[o + 14], 23, -35309556)),
+                  (r = d(r, n, s, i, e[o + 1], 4, -1530992060)),
+                  (i = d(i, r, n, s, e[o + 4], 11, 1272893353)),
+                  (s = d(s, i, r, n, e[o + 7], 16, -155497632)),
+                  (n = d(n, s, i, r, e[o + 10], 23, -1094730640)),
+                  (r = d(r, n, s, i, e[o + 13], 4, 681279174)),
+                  (i = d(i, r, n, s, e[o + 0], 11, -358537222)),
+                  (s = d(s, i, r, n, e[o + 3], 16, -722521979)),
+                  (n = d(n, s, i, r, e[o + 6], 23, 76029189)),
+                  (r = d(r, n, s, i, e[o + 9], 4, -640364487)),
+                  (i = d(i, r, n, s, e[o + 12], 11, -421815835)),
+                  (s = d(s, i, r, n, e[o + 15], 16, 530742520)),
+                  (r = h(r, (n = d(n, s, i, r, e[o + 2], 23, -995338651)), s, i, e[o + 0], 6, -198630844)),
+                  (i = h(i, r, n, s, e[o + 7], 10, 1126891415)),
+                  (s = h(s, i, r, n, e[o + 14], 15, -1416354905)),
+                  (n = h(n, s, i, r, e[o + 5], 21, -57434055)),
+                  (r = h(r, n, s, i, e[o + 12], 6, 1700485571)),
+                  (i = h(i, r, n, s, e[o + 3], 10, -1894986606)),
+                  (s = h(s, i, r, n, e[o + 10], 15, -1051523)),
+                  (n = h(n, s, i, r, e[o + 1], 21, -2054922799)),
+                  (r = h(r, n, s, i, e[o + 8], 6, 1873313359)),
+                  (i = h(i, r, n, s, e[o + 15], 10, -30611744)),
+                  (s = h(s, i, r, n, e[o + 6], 15, -1560198380)),
+                  (n = h(n, s, i, r, e[o + 13], 21, 1309151649)),
+                  (r = h(r, n, s, i, e[o + 4], 6, -145523070)),
+                  (i = h(i, r, n, s, e[o + 11], 10, -1120210379)),
+                  (s = h(s, i, r, n, e[o + 2], 15, 718787259)),
+                  (n = h(n, s, i, r, e[o + 9], 21, -343485551)),
+                  (r = m(r, a)),
+                  (n = m(n, c)),
+                  (s = m(s, l)),
+                  (i = m(i, u));
+              }
+              return Array(r, n, s, i);
+            }
+            function a(e, t, r, n, s, i) {
+              return m(((t = m(m(t, e), m(n, i))) << s) | (t >>> (32 - s)), r);
+            }
+            function p(e, t, r, n, s, i, o) {
+              return a((t & r) | (~t & n), e, t, s, i, o);
+            }
+            function f(e, t, r, n, s, i, o) {
+              return a((t & n) | (r & ~n), e, t, s, i, o);
+            }
+            function d(e, t, r, n, s, i, o) {
+              return a(t ^ r ^ n, e, t, s, i, o);
+            }
+            function h(e, t, r, n, s, i, o) {
+              return a(r ^ (t | ~n), e, t, s, i, o);
+            }
+            function m(e, t) {
+              var r = (65535 & e) + (65535 & t);
+              return (((e >> 16) + (t >> 16) + (r >> 16)) << 16) | (65535 & r);
+            }
+            t.exports = function (e) {
+              return n.hash(e, s, 16);
+            };
+          },
+          { './helpers': 436 }
+        ],
+        438: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('./helpers');
+            function s(e, t) {
+              (e[t >> 5] |= 128 << (24 - (t % 32))), (e[15 + (((t + 64) >> 9) << 4)] = t);
+              for (
+                var r,
+                  n,
+                  s,
+                  i = Array(80),
+                  o = 1732584193,
+                  a = -271733879,
+                  c = -1732584194,
+                  l = 271733878,
+                  u = -1009589776,
+                  p = 0;
+                p < e.length;
+                p += 16
+              ) {
+                for (var f = o, d = a, h = c, m = l, y = u, b = 0; b < 80; b++) {
+                  i[b] = b < 16 ? e[p + b] : j(i[b - 3] ^ i[b - 8] ^ i[b - 14] ^ i[b - 16], 1);
+                  var g = v(
+                      v(
+                        j(o, 5),
+                        ((g = a),
+                        (n = c),
+                        (s = l),
+                        (r = b) < 20
+                          ? (g & n) | (~g & s)
+                          : !(r < 40) && r < 60
+                          ? (g & n) | (g & s) | (n & s)
+                          : g ^ n ^ s)
+                      ),
+                      v(v(u, i[b]), (r = b) < 20 ? 1518500249 : r < 40 ? 1859775393 : r < 60 ? -1894007588 : -899497514)
+                    ),
+                    u = l,
+                    l = c,
+                    c = j(a, 30),
+                    a = o,
+                    o = g;
+                }
+                (o = v(o, f)), (a = v(a, d)), (c = v(c, h)), (l = v(l, m)), (u = v(u, y));
+              }
+              return Array(o, a, c, l, u);
+            }
+            function v(e, t) {
+              var r = (65535 & e) + (65535 & t);
+              return (((e >> 16) + (t >> 16) + (r >> 16)) << 16) | (65535 & r);
+            }
+            function j(e, t) {
+              return (e << t) | (e >>> (32 - t));
+            }
+            t.exports = function (e) {
+              return n.hash(e, s, 20, !0);
+            };
+          },
+          { './helpers': 436 }
+        ],
+        439: [
+          function (e, t, r) {
+            'use strict';
+            t.exports = function () {
+              return function () {};
+            };
+          },
+          {}
+        ],
+        440: [
+          function (s, i, e) {
+            !function (n) {
+              !function () {
+                'use strict';
+                var t = s('@babel/runtime/helpers/interopRequireDefault')(s('@babel/runtime/helpers/typeof')),
+                  r = s('stream').Stream,
+                  e = s('../lib/common/utils/isArray').isArray;
+                (i.exports.string = function (e) {
+                  return 'string' == typeof e;
+                }),
+                  (i.exports.array = e),
+                  (i.exports.buffer = n.isBuffer),
+                  (i.exports.writableStream = function (e) {
+                    return (
+                      e instanceof r && 'function' == typeof e._write && 'object' === (0, t.default)(e._writableState)
+                    );
+                  });
+              }.call(this);
+            }.call(this, { isBuffer: s('../node_modules/is-buffer/index.js') });
+          },
+          {
+            '../lib/common/utils/isArray': 62,
+            '../node_modules/is-buffer/index.js': 354,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            stream: 387
+          }
+        ],
+        441: [
+          function (e, t, r) {
+            'use strict';
+            (e = e('immediate')), (t = t.exports = {});
+            function n() {}
+            (t.nextTick = e),
+              (t.title = 'browser'),
+              (t.browser = !0),
+              (t.env = {}),
+              (t.argv = []),
+              (t.version = ''),
+              (t.versions = {}),
+              (t.on = n),
+              (t.addListener = n),
+              (t.once = n),
+              (t.off = n),
+              (t.removeListener = n),
+              (t.removeAllListeners = n),
+              (t.emit = n),
+              (t.prependListener = n),
+              (t.prependOnceListener = n),
+              (t.listeners = function (e) {
+                return [];
+              }),
+              (t.binding = function (e) {
+                throw new Error('process.binding is not supported');
+              }),
+              (t.cwd = function () {
+                return '/';
+              }),
+              (t.chdir = function (e) {
+                throw new Error('process.chdir is not supported');
+              }),
+              (t.umask = function () {
+                return 0;
+              });
+          },
+          { immediate: 347 }
+        ],
+        442: [
+          function (n, e, s) {
+            !function (l) {
+              !function () {
+                'use strict';
+                n('core-js/modules/es.regexp.exec.js'), n('core-js/modules/es.string.search.js');
+                var o = n('./lib/request'),
+                  e = n('./lib/response'),
+                  a = n('xtend'),
+                  t = n('builtin-status-codes'),
+                  c = n('url'),
+                  r = s;
+                (r.request = function (e, t) {
+                  e = 'string' == typeof e ? c.parse(e) : a(e);
+                  var r = -1 === l.location.protocol.search(/^https?:$/) ? 'http:' : '',
+                    r = e.protocol || r,
+                    n = e.hostname || e.host,
+                    s = e.port,
+                    i = e.path || '/',
+                    r =
+                      (n && -1 !== n.indexOf(':') && (n = '[' + n + ']'),
+                      (e.url = (n ? r + '//' + n : '') + (s ? ':' + s : '') + i),
+                      (e.method = (e.method || 'GET').toUpperCase()),
+                      (e.headers = e.headers || {}),
+                      new o(e));
+                  return t && r.on('response', t), r;
+                }),
+                  (r.get = function (e, t) {
+                    e = r.request(e, t);
+                    return e.end(), e;
+                  }),
+                  (r.ClientRequest = o),
+                  (r.IncomingMessage = e.IncomingMessage),
+                  (r.Agent = function () {}),
+                  (r.Agent.defaultMaxSockets = 4),
+                  (r.globalAgent = new r.Agent()),
+                  (r.STATUS_CODES = t),
+                  (r.METHODS = [
+                    'CHECKOUT',
+                    'CONNECT',
+                    'COPY',
+                    'DELETE',
+                    'GET',
+                    'HEAD',
+                    'LOCK',
+                    'M-SEARCH',
+                    'MERGE',
+                    'MKACTIVITY',
+                    'MKCOL',
+                    'MOVE',
+                    'NOTIFY',
+                    'OPTIONS',
+                    'PATCH',
+                    'POST',
+                    'PROPFIND',
+                    'PROPPATCH',
+                    'PURGE',
+                    'PUT',
+                    'REPORT',
+                    'SEARCH',
+                    'SUBSCRIBE',
+                    'TRACE',
+                    'UNLOCK',
+                    'UNSUBSCRIBE'
+                  ]);
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {
+            './lib/request': 444,
+            './lib/response': 445,
+            'builtin-status-codes': 90,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.search.js': 305,
+            url: 446,
+            xtend: 434
+          }
+        ],
+        443: [
+          function (a, e, c) {
+            !function (o) {
+              !function () {
+                'use strict';
+                a('core-js/modules/es.object.to-string.js'),
+                  a('core-js/modules/es.promise.js'),
+                  a('core-js/modules/es.array-buffer.constructor.js'),
+                  a('core-js/modules/es.array-buffer.slice.js'),
+                  a('core-js/modules/es.array.slice.js'),
+                  (c.fetch = i(o.fetch) && i(o.ReadableStream)),
+                  (c.writableStream = i(o.WritableStream)),
+                  (c.abortController = i(o.AbortController)),
+                  (c.blobConstructor = !1);
+                try {
+                  new Blob([new ArrayBuffer(1)]), (c.blobConstructor = !0);
+                } catch (e) {}
+                var t;
+                function r() {
+                  if (void 0 !== t) return t;
+                  if (o.XMLHttpRequest) {
+                    t = new o.XMLHttpRequest();
+                    try {
+                      t.open('GET', o.XDomainRequest ? '/' : 'https://example.com');
+                    } catch (e) {
+                      t = null;
+                    }
+                  } else t = null;
+                  return t;
+                }
+                function e(e) {
+                  var t = r();
+                  if (!t) return !1;
+                  try {
+                    return (t.responseType = e), t.responseType === e;
+                  } catch (e) {}
+                  return !1;
+                }
+                var n = void 0 !== o.ArrayBuffer,
+                  s = n && i(o.ArrayBuffer.prototype.slice);
+                function i(e) {
+                  return 'function' == typeof e;
+                }
+                (c.arraybuffer = c.fetch || (n && e('arraybuffer'))),
+                  (c.msstream = !c.fetch && s && e('ms-stream')),
+                  (c.mozchunkedarraybuffer = !c.fetch && n && e('moz-chunked-arraybuffer')),
+                  (c.overrideMimeType = c.fetch || (!!r() && i(r().overrideMimeType))),
+                  (c.vbArray = i(o.VBArray)),
+                  (t = null);
+              }.call(this);
+            }.call(
+              this,
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {}
+            );
+          },
+          {
+            'core-js/modules/es.array-buffer.constructor.js': 267,
+            'core-js/modules/es.array-buffer.slice.js': 268,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294
+          }
+        ],
+        444: [
+          function (i, o, e) {
+            !function (p, f, d) {
+              !function () {
+                'use strict';
+                i('core-js/modules/es.object.to-string.js'),
+                  i('core-js/modules/es.regexp.to-string.js'),
+                  i('core-js/modules/web.dom-collections.for-each.js'),
+                  i('core-js/modules/es.object.keys.js'),
+                  i('core-js/modules/es.array.concat.js'),
+                  i('core-js/modules/es.array.map.js'),
+                  i('core-js/modules/es.function.name.js'),
+                  i('core-js/modules/es.promise.js'),
+                  i('core-js/modules/es.regexp.exec.js'),
+                  i('core-js/modules/es.string.split.js');
+                var c = i('./capability'),
+                  e = i('inherits'),
+                  t = i('./response'),
+                  s = i('readable-stream'),
+                  l = i('to-arraybuffer'),
+                  r = t.IncomingMessage,
+                  u = t.readyStates;
+                t = o.exports = function (t) {
+                  var e,
+                    r = this,
+                    n =
+                      (s.Writable.call(r),
+                      (r._opts = t),
+                      (r._body = []),
+                      (r._headers = {}),
+                      t.auth && r.setHeader('Authorization', 'Basic ' + new d(t.auth).toString('base64')),
+                      Object.keys(t.headers).forEach(function (e) {
+                        r.setHeader(e, t.headers[e]);
+                      }),
+                      !0);
+                  if ('disable-fetch' === t.mode || ('requestTimeout' in t && !c.abortController)) e = !(n = !1);
+                  else if ('prefer-streaming' === t.mode) e = !1;
+                  else if ('allow-wrong-content-type' === t.mode) e = !c.overrideMimeType;
+                  else {
+                    if (t.mode && 'default' !== t.mode && 'prefer-fast' !== t.mode)
+                      throw new Error('Invalid value for opts.mode');
+                    e = !0;
+                  }
+                  (r._mode =
+                    ((e = e),
+                    (n = n),
+                    c.fetch && n
+                      ? 'fetch'
+                      : c.mozchunkedarraybuffer
+                      ? 'moz-chunked-arraybuffer'
+                      : c.msstream
+                      ? 'ms-stream'
+                      : c.arraybuffer && e
+                      ? 'arraybuffer'
+                      : c.vbArray && e
+                      ? 'text:vbarray'
+                      : 'text')),
+                    (r._fetchTimer = null),
+                    r.on('finish', function () {
+                      r._onFinish();
+                    });
+                };
+                e(t, s.Writable),
+                  (t.prototype.setHeader = function (e, t) {
+                    var r = e.toLowerCase();
+                    -1 === n.indexOf(r) && (this._headers[r] = { name: e, value: t });
+                  }),
+                  (t.prototype.getHeader = function (e) {
+                    e = this._headers[e.toLowerCase()];
+                    return e ? e.value : null;
+                  }),
+                  (t.prototype.removeHeader = function (e) {
+                    delete this._headers[e.toLowerCase()];
+                  }),
+                  (t.prototype._onFinish = function () {
+                    var t = this;
+                    if (!t._destroyed) {
+                      var e = t._opts,
+                        r = t._headers,
+                        n = null,
+                        s =
+                          ('GET' !== e.method &&
+                            'HEAD' !== e.method &&
+                            (n = c.arraybuffer
+                              ? l(d.concat(t._body))
+                              : c.blobConstructor
+                              ? new f.Blob(
+                                  t._body.map(function (e) {
+                                    return l(e);
+                                  }),
+                                  { type: (r['content-type'] || {}).value || '' }
+                                )
+                              : d.concat(t._body).toString()),
+                          []);
+                      if (
+                        (Object.keys(r).forEach(function (e) {
+                          var t = r[e].name,
+                            e = r[e].value;
+                          Array.isArray(e)
+                            ? e.forEach(function (e) {
+                                s.push([t, e]);
+                              })
+                            : s.push([t, e]);
+                        }),
+                        'fetch' === t._mode)
+                      ) {
+                        var i,
+                          o = null;
+                        c.abortController &&
+                          ((o = (i = new AbortController()).signal),
+                          (t._fetchAbortController = i),
+                          'requestTimeout' in e &&
+                            0 !== e.requestTimeout &&
+                            (t._fetchTimer = f.setTimeout(function () {
+                              t.emit('requestTimeout'), t._fetchAbortController && t._fetchAbortController.abort();
+                            }, e.requestTimeout))),
+                          f
+                            .fetch(t._opts.url, {
+                              method: t._opts.method,
+                              headers: s,
+                              body: n || void 0,
+                              mode: 'cors',
+                              credentials: e.withCredentials ? 'include' : 'same-origin',
+                              signal: o
+                            })
+                            .then(
+                              function (e) {
+                                (t._fetchResponse = e), t._connect();
+                              },
+                              function (e) {
+                                f.clearTimeout(t._fetchTimer), t._destroyed || t.emit('error', e);
+                              }
+                            );
+                      } else {
+                        var a = (t._xhr = new f.XMLHttpRequest());
+                        try {
+                          a.open(t._opts.method, t._opts.url, !0);
+                        } catch (e) {
+                          return void p.nextTick(function () {
+                            t.emit('error', e);
+                          });
+                        }
+                        'responseType' in a && (a.responseType = t._mode.split(':')[0]),
+                          'withCredentials' in a && (a.withCredentials = !!e.withCredentials),
+                          'text' === t._mode &&
+                            'overrideMimeType' in a &&
+                            a.overrideMimeType('text/plain; charset=x-user-defined'),
+                          'requestTimeout' in e &&
+                            ((a.timeout = e.requestTimeout),
+                            (a.ontimeout = function () {
+                              t.emit('requestTimeout');
+                            })),
+                          s.forEach(function (e) {
+                            a.setRequestHeader(e[0], e[1]);
+                          }),
+                          (t._response = null),
+                          (a.onreadystatechange = function () {
+                            switch (a.readyState) {
+                              case u.LOADING:
+                              case u.DONE:
+                                t._onXHRProgress();
+                            }
+                          }),
+                          'moz-chunked-arraybuffer' === t._mode &&
+                            (a.onprogress = function () {
+                              t._onXHRProgress();
+                            }),
+                          (a.onerror = function () {
+                            t._destroyed || t.emit('error', new Error('XHR error'));
+                          });
+                        try {
+                          a.send(n);
+                        } catch (e) {
+                          return void p.nextTick(function () {
+                            t.emit('error', e);
+                          });
+                        }
+                      }
+                    }
+                  }),
+                  (t.prototype._onXHRProgress = function () {
+                    !(function (e) {
+                      try {
+                        var t = e.status;
+                        return null !== t && 0 !== t;
+                      } catch (e) {
+                        return;
+                      }
+                    })(this._xhr) ||
+                      this._destroyed ||
+                      (this._response || this._connect(), this._response._onXHRProgress());
+                  }),
+                  (t.prototype._connect = function () {
+                    var t = this;
+                    t._destroyed ||
+                      ((t._response = new r(t._xhr, t._fetchResponse, t._mode, t._fetchTimer)),
+                      t._response.on('error', function (e) {
+                        t.emit('error', e);
+                      }),
+                      t.emit('response', t._response));
+                  }),
+                  (t.prototype._write = function (e, t, r) {
+                    this._body.push(e), r();
+                  }),
+                  (t.prototype.abort = t.prototype.destroy =
+                    function () {
+                      (this._destroyed = !0),
+                        f.clearTimeout(this._fetchTimer),
+                        this._response && (this._response._destroyed = !0),
+                        this._xhr
+                          ? this._xhr.abort()
+                          : this._fetchAbortController && this._fetchAbortController.abort();
+                    }),
+                  (t.prototype.end = function (e, t, r) {
+                    'function' == typeof e && ((r = e), (e = void 0)), s.Writable.prototype.end.call(this, e, t, r);
+                  }),
+                  (t.prototype.flushHeaders = function () {}),
+                  (t.prototype.setTimeout = function () {}),
+                  (t.prototype.setNoDelay = function () {}),
+                  (t.prototype.setSocketKeepAlive = function () {});
+                var n = [
+                  'accept-charset',
+                  'accept-encoding',
+                  'access-control-request-headers',
+                  'access-control-request-method',
+                  'connection',
+                  'content-length',
+                  'cookie',
+                  'cookie2',
+                  'date',
+                  'dnt',
+                  'expect',
+                  'host',
+                  'keep-alive',
+                  'origin',
+                  'referer',
+                  'te',
+                  'trailer',
+                  'transfer-encoding',
+                  'upgrade',
+                  'user-agent',
+                  'via'
+                ];
+              }.call(this);
+            }.call(
+              this,
+              i('_process'),
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {},
+              i('buffer').Buffer
+            );
+          },
+          {
+            './capability': 443,
+            './response': 445,
+            _process: 441,
+            buffer: 89,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.map.js': 277,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.regexp.to-string.js': 300,
+            'core-js/modules/es.string.split.js': 306,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            inherits: 353,
+            'readable-stream': 381,
+            'to-arraybuffer': 390
+          }
+        ],
+        445: [
+          function (r, e, n) {
+            !function (u, p, f) {
+              !function () {
+                'use strict';
+                r('core-js/modules/es.object.to-string.js'),
+                  r('core-js/modules/web.dom-collections.for-each.js'),
+                  r('core-js/modules/es.promise.js'),
+                  r('core-js/modules/es.regexp.exec.js'),
+                  r('core-js/modules/es.string.split.js'),
+                  r('core-js/modules/es.string.match.js'),
+                  r('core-js/modules/es.array.iterator.js'),
+                  r('core-js/modules/es.array-buffer.slice.js'),
+                  r('core-js/modules/es.typed-array.uint8-array.js'),
+                  r('core-js/modules/es.typed-array.copy-within.js'),
+                  r('core-js/modules/es.typed-array.every.js'),
+                  r('core-js/modules/es.typed-array.fill.js'),
+                  r('core-js/modules/es.typed-array.filter.js'),
+                  r('core-js/modules/es.typed-array.find.js'),
+                  r('core-js/modules/es.typed-array.find-index.js'),
+                  r('core-js/modules/es.typed-array.for-each.js'),
+                  r('core-js/modules/es.typed-array.includes.js'),
+                  r('core-js/modules/es.typed-array.index-of.js'),
+                  r('core-js/modules/es.typed-array.iterator.js'),
+                  r('core-js/modules/es.typed-array.join.js'),
+                  r('core-js/modules/es.typed-array.last-index-of.js'),
+                  r('core-js/modules/es.typed-array.map.js'),
+                  r('core-js/modules/es.typed-array.reduce.js'),
+                  r('core-js/modules/es.typed-array.reduce-right.js'),
+                  r('core-js/modules/es.typed-array.reverse.js'),
+                  r('core-js/modules/es.typed-array.set.js'),
+                  r('core-js/modules/es.typed-array.slice.js'),
+                  r('core-js/modules/es.typed-array.some.js'),
+                  r('core-js/modules/es.typed-array.sort.js'),
+                  r('core-js/modules/es.typed-array.subarray.js'),
+                  r('core-js/modules/es.typed-array.to-locale-string.js'),
+                  r('core-js/modules/es.typed-array.to-string.js'),
+                  r('core-js/modules/es.array.slice.js');
+                var a = r('./capability'),
+                  e = r('inherits'),
+                  c = r('readable-stream'),
+                  l = (n.readyStates = { UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4 }),
+                  t = (n.IncomingMessage = function (e, t, r, n) {
+                    var s = this;
+                    if (
+                      (c.Readable.call(s),
+                      (s._mode = r),
+                      (s.headers = {}),
+                      (s.rawHeaders = []),
+                      (s.trailers = {}),
+                      (s.rawTrailers = []),
+                      s.on('end', function () {
+                        u.nextTick(function () {
+                          s.emit('close');
+                        });
+                      }),
+                      'fetch' === r)
+                    ) {
+                      r = function t() {
+                        o.read()
+                          .then(function (e) {
+                            if (!s._destroyed) {
+                              if (e.done) return p.clearTimeout(n), void s.push(null);
+                              s.push(new f(e.value)), t();
+                            }
+                          })
+                          .catch(function (e) {
+                            p.clearTimeout(n), s._destroyed || s.emit('error', e);
+                          });
+                      };
+                      if (
+                        ((s._fetchResponse = t),
+                        (s.url = t.url),
+                        (s.statusCode = t.status),
+                        (s.statusMessage = t.statusText),
+                        t.headers.forEach(function (e, t) {
+                          (s.headers[t.toLowerCase()] = e), s.rawHeaders.push(t, e);
+                        }),
+                        a.writableStream)
+                      ) {
+                        var i = new WritableStream({
+                          write: function (r) {
+                            return new Promise(function (e, t) {
+                              s._destroyed ? t() : s.push(new f(r)) ? e() : (s._resumeFetch = e);
+                            });
+                          },
+                          close: function () {
+                            p.clearTimeout(n), s._destroyed || s.push(null);
+                          },
+                          abort: function (e) {
+                            s._destroyed || s.emit('error', e);
+                          }
+                        });
+                        try {
+                          return void t.body.pipeTo(i).catch(function (e) {
+                            p.clearTimeout(n), s._destroyed || s.emit('error', e);
+                          });
+                        } catch (e) {}
+                      }
+                      var o = t.body.getReader();
+                      r();
+                    } else
+                      (s._xhr = e),
+                        (s._pos = 0),
+                        (s.url = e.responseURL),
+                        (s.statusCode = e.status),
+                        (s.statusMessage = e.statusText),
+                        e
+                          .getAllResponseHeaders()
+                          .split(/\r?\n/)
+                          .forEach(function (e) {
+                            var t,
+                              e = e.match(/^([^:]+):\s*(.*)/);
+                            e &&
+                              ('set-cookie' === (t = e[1].toLowerCase())
+                                ? (void 0 === s.headers[t] && (s.headers[t] = []), s.headers[t].push(e[2]))
+                                : void 0 !== s.headers[t]
+                                ? (s.headers[t] += ', ' + e[2])
+                                : (s.headers[t] = e[2]),
+                              s.rawHeaders.push(e[1], e[2]));
+                          }),
+                        (s._charset = 'x-user-defined'),
+                        a.overrideMimeType ||
+                          ((i = s.rawHeaders['mime-type']) &&
+                            (t = i.match(/;\s*charset=([^;])(;|$)/)) &&
+                            (s._charset = t[1].toLowerCase()),
+                          s._charset || (s._charset = 'utf-8'));
+                  });
+                e(t, c.Readable),
+                  (t.prototype._read = function () {
+                    var e = this._resumeFetch;
+                    e && ((this._resumeFetch = null), e());
+                  }),
+                  (t.prototype._onXHRProgress = function () {
+                    var t = this,
+                      e = t._xhr,
+                      r = null;
+                    switch (t._mode) {
+                      case 'text:vbarray':
+                        if (e.readyState !== l.DONE) break;
+                        try {
+                          r = new p.VBArray(e.responseBody).toArray();
+                        } catch (e) {}
+                        if (null !== r) {
+                          t.push(new f(r));
+                          break;
+                        }
+                      case 'text':
+                        try {
+                          r = e.responseText;
+                        } catch (e) {
+                          t._mode = 'text:vbarray';
+                          break;
+                        }
+                        if (r.length > t._pos) {
+                          var n = r.substr(t._pos);
+                          if ('x-user-defined' === t._charset) {
+                            for (var s = new f(n.length), i = 0; i < n.length; i++) s[i] = 255 & n.charCodeAt(i);
+                            t.push(s);
+                          } else t.push(n, t._charset);
+                          t._pos = r.length;
+                        }
+                        break;
+                      case 'arraybuffer':
+                        if (e.readyState !== l.DONE || !e.response) break;
+                        (r = e.response), t.push(new f(new Uint8Array(r)));
+                        break;
+                      case 'moz-chunked-arraybuffer':
+                        if (((r = e.response), e.readyState !== l.LOADING || !r)) break;
+                        t.push(new f(new Uint8Array(r)));
+                        break;
+                      case 'ms-stream':
+                        if (((r = e.response), e.readyState !== l.LOADING)) break;
+                        var o = new p.MSStreamReader();
+                        (o.onprogress = function () {
+                          o.result.byteLength > t._pos &&
+                            (t.push(new f(new Uint8Array(o.result.slice(t._pos)))), (t._pos = o.result.byteLength));
+                        }),
+                          (o.onload = function () {
+                            t.push(null);
+                          }),
+                          o.readAsArrayBuffer(r);
+                    }
+                    t._xhr.readyState === l.DONE && 'ms-stream' !== t._mode && t.push(null);
+                  });
+              }.call(this);
+            }.call(
+              this,
+              r('_process'),
+              'undefined' != typeof global
+                ? global
+                : 'undefined' != typeof self
+                ? self
+                : 'undefined' != typeof window
+                ? window
+                : {},
+              r('buffer').Buffer
+            );
+          },
+          {
+            './capability': 443,
+            _process: 441,
+            buffer: 89,
+            'core-js/modules/es.array-buffer.slice.js': 268,
+            'core-js/modules/es.array.iterator.js': 275,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.match.js': 303,
+            'core-js/modules/es.string.split.js': 306,
+            'core-js/modules/es.typed-array.copy-within.js': 314,
+            'core-js/modules/es.typed-array.every.js': 315,
+            'core-js/modules/es.typed-array.fill.js': 316,
+            'core-js/modules/es.typed-array.filter.js': 317,
+            'core-js/modules/es.typed-array.find-index.js': 318,
+            'core-js/modules/es.typed-array.find.js': 319,
+            'core-js/modules/es.typed-array.for-each.js': 320,
+            'core-js/modules/es.typed-array.includes.js': 321,
+            'core-js/modules/es.typed-array.index-of.js': 322,
+            'core-js/modules/es.typed-array.iterator.js': 323,
+            'core-js/modules/es.typed-array.join.js': 324,
+            'core-js/modules/es.typed-array.last-index-of.js': 325,
+            'core-js/modules/es.typed-array.map.js': 326,
+            'core-js/modules/es.typed-array.reduce-right.js': 327,
+            'core-js/modules/es.typed-array.reduce.js': 328,
+            'core-js/modules/es.typed-array.reverse.js': 329,
+            'core-js/modules/es.typed-array.set.js': 330,
+            'core-js/modules/es.typed-array.slice.js': 331,
+            'core-js/modules/es.typed-array.some.js': 332,
+            'core-js/modules/es.typed-array.sort.js': 333,
+            'core-js/modules/es.typed-array.subarray.js': 334,
+            'core-js/modules/es.typed-array.to-locale-string.js': 335,
+            'core-js/modules/es.typed-array.to-string.js': 336,
+            'core-js/modules/es.typed-array.uint8-array.js': 337,
+            'core-js/modules/web.dom-collections.for-each.js': 338,
+            inherits: 353,
+            'readable-stream': 381
+          }
+        ],
+        446: [
+          function (e, t, r) {
+            'use strict';
+            var T = e('@babel/runtime/helpers/interopRequireDefault')(e('@babel/runtime/helpers/typeof')),
+              k =
+                (e('core-js/modules/es.regexp.exec.js'),
+                e('core-js/modules/es.string.search.js'),
+                e('core-js/modules/es.array.concat.js'),
+                e('core-js/modules/es.string.split.js'),
+                e('core-js/modules/es.string.replace.js'),
+                e('core-js/modules/es.array.join.js'),
+                e('core-js/modules/es.string.trim.js'),
+                e('core-js/modules/es.string.match.js'),
+                e('core-js/modules/es.array.slice.js'),
+                e('core-js/modules/es.object.keys.js'),
+                e('core-js/modules/es.array.splice.js'),
+                e('punycode')),
+              E = e('./util');
+            function w() {
+              (this.protocol = null),
+                (this.slashes = null),
+                (this.auth = null),
+                (this.host = null),
+                (this.port = null),
+                (this.hostname = null),
+                (this.hash = null),
+                (this.search = null),
+                (this.query = null),
+                (this.pathname = null),
+                (this.path = null),
+                (this.href = null);
+            }
+            (r.parse = s),
+              (r.resolve = function (e, t) {
+                return s(e, !1, !0).resolve(t);
+              }),
+              (r.resolveObject = function (e, t) {
+                return e ? s(e, !1, !0).resolveObject(t) : t;
+              }),
+              (r.format = function (e) {
+                E.isString(e) && (e = s(e));
+                return e instanceof w ? e.format() : w.prototype.format.call(e);
+              }),
+              (r.Url = w);
+            var _ = /^([a-z0-9.+-]+:)/i,
+              n = /:[0-9]*$/,
+              S = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
+              r = ['{', '}', '|', '\\', '^', '`'].concat(['<', '>', '"', '`', ' ', '\r', '\n', '\t']),
+              O = ["'"].concat(r),
+              A = ['%', '/', '?', ';', '#'].concat(O),
+              D = ['/', '?', '#'],
+              I = /^[+a-z0-9A-Z_-]{0,63}$/,
+              C = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
+              N = { javascript: !0, 'javascript:': !0 },
+              R = { javascript: !0, 'javascript:': !0 },
+              P = {
+                http: !0,
+                https: !0,
+                ftp: !0,
+                gopher: !0,
+                file: !0,
+                'http:': !0,
+                'https:': !0,
+                'ftp:': !0,
+                'gopher:': !0,
+                'file:': !0
+              },
+              M = e('querystring');
+            function s(e, t, r) {
+              if (e && E.isObject(e) && e instanceof w) return e;
+              var n = new w();
+              return n.parse(e, t, r), n;
+            }
+            (w.prototype.parse = function (e, t, r) {
+              if (!E.isString(e)) throw new TypeError("Parameter 'url' must be a string, not " + (0, T.default)(e));
+              var n = e.indexOf('?'),
+                n = -1 !== n && n < e.indexOf('#') ? '?' : '#',
+                s = e.split(n);
+              s[0] = s[0].replace(/\\/g, '/');
+              var i = (i = e = s.join(n)).trim();
+              if (!r && 1 === e.split('#').length) {
+                s = S.exec(i);
+                if (s)
+                  return (
+                    (this.path = i),
+                    (this.href = i),
+                    (this.pathname = s[1]),
+                    s[2]
+                      ? ((this.search = s[2]),
+                        (this.query = t ? M.parse(this.search.substr(1)) : this.search.substr(1)))
+                      : t && ((this.search = ''), (this.query = {})),
+                    this
+                  );
+              }
+              var o,
+                n = _.exec(i);
+              if (
+                (n && ((o = (n = n[0]).toLowerCase()), (this.protocol = o), (i = i.substr(n.length))),
+                !(r || n || i.match(/^\/\/[^@\/]+@[^@\/]+/)) ||
+                  !(j = '//' === i.substr(0, 2)) ||
+                  (n && R[n]) ||
+                  ((i = i.substr(2)), (this.slashes = !0)),
+                !R[n] && (j || (n && !P[n])))
+              ) {
+                for (var a = -1, c = 0; c < D.length; c++)
+                  -1 !== (l = i.indexOf(D[c])) && (-1 === a || l < a) && (a = l);
+                -1 !== (e = -1 === a ? i.lastIndexOf('@') : i.lastIndexOf('@', a)) &&
+                  ((s = i.slice(0, e)), (i = i.slice(e + 1)), (this.auth = decodeURIComponent(s)));
+                for (var l, a = -1, c = 0; c < A.length; c++)
+                  -1 !== (l = i.indexOf(A[c])) && (-1 === a || l < a) && (a = l);
+                -1 === a && (a = i.length),
+                  (this.host = i.slice(0, a)),
+                  (i = i.slice(a)),
+                  this.parseHost(),
+                  (this.hostname = this.hostname || '');
+                r = '[' === this.hostname[0] && ']' === this.hostname[this.hostname.length - 1];
+                if (!r)
+                  for (var u = this.hostname.split('.'), c = 0, p = u.length; c < p; c++) {
+                    var f = u[c];
+                    if (f && !f.match(I)) {
+                      for (var d = '', h = 0, m = f.length; h < m; h++)
+                        127 < f.charCodeAt(h) ? (d += 'x') : (d += f[h]);
+                      if (!d.match(I)) {
+                        var y = u.slice(0, c),
+                          b = u.slice(c + 1),
+                          g = f.match(C);
+                        g && (y.push(g[1]), b.unshift(g[2])),
+                          b.length && (i = '/' + b.join('.') + i),
+                          (this.hostname = y.join('.'));
+                        break;
+                      }
+                    }
+                  }
+                255 < this.hostname.length ? (this.hostname = '') : (this.hostname = this.hostname.toLowerCase()),
+                  r || (this.hostname = k.toASCII(this.hostname));
+                var v = this.port ? ':' + this.port : '',
+                  j = this.hostname || '';
+                (this.host = j + v),
+                  (this.href += this.host),
+                  r &&
+                    ((this.hostname = this.hostname.substr(1, this.hostname.length - 2)),
+                    '/' !== i[0] && (i = '/' + i));
+              }
+              if (!N[o])
+                for (c = 0, p = O.length; c < p; c++) {
+                  var w,
+                    x = O[c];
+                  -1 !== i.indexOf(x) &&
+                    ((w = encodeURIComponent(x)) === x && (w = escape(x)), (i = i.split(x).join(w)));
+                }
+              (n = i.indexOf('#')), -1 !== n && ((this.hash = i.substr(n)), (i = i.slice(0, n))), (e = i.indexOf('?'));
+              return (
+                -1 !== e
+                  ? ((this.search = i.substr(e)),
+                    (this.query = i.substr(e + 1)),
+                    t && (this.query = M.parse(this.query)),
+                    (i = i.slice(0, e)))
+                  : t && ((this.search = ''), (this.query = {})),
+                i && (this.pathname = i),
+                P[o] && this.hostname && !this.pathname && (this.pathname = '/'),
+                (this.pathname || this.search) &&
+                  ((v = this.pathname || ''), (s = this.search || ''), (this.path = v + s)),
+                (this.href = this.format()),
+                this
+              );
+            }),
+              (w.prototype.format = function () {
+                var e = this.auth || '',
+                  t = (e && ((e = (e = encodeURIComponent(e)).replace(/%3A/i, ':')), (e += '@')), this.protocol || ''),
+                  r = this.pathname || '',
+                  n = this.hash || '',
+                  s = !1,
+                  i = '',
+                  e =
+                    (this.host
+                      ? (s = e + this.host)
+                      : this.hostname &&
+                        ((s = e + (-1 === this.hostname.indexOf(':') ? this.hostname : '[' + this.hostname + ']')),
+                        this.port && (s += ':' + this.port)),
+                    this.query &&
+                      E.isObject(this.query) &&
+                      Object.keys(this.query).length &&
+                      (i = M.stringify(this.query)),
+                    this.search || (i && '?' + i) || '');
+                return (
+                  t && ':' !== t.substr(-1) && (t += ':'),
+                  this.slashes || ((!t || P[t]) && !1 !== s)
+                    ? ((s = '//' + (s || '')), r && '/' !== r.charAt(0) && (r = '/' + r))
+                    : (s = s || ''),
+                  n && '#' !== n.charAt(0) && (n = '#' + n),
+                  e && '?' !== e.charAt(0) && (e = '?' + e),
+                  t +
+                    s +
+                    (r = r.replace(/[?#]/g, function (e) {
+                      return encodeURIComponent(e);
+                    })) +
+                    (e = e.replace('#', '%23')) +
+                    n
+                );
+              }),
+              (w.prototype.resolve = function (e) {
+                return this.resolveObject(s(e, !1, !0)).format();
+              }),
+              (w.prototype.resolveObject = function (e) {
+                E.isString(e) && ((f = new w()).parse(e, !1, !0), (e = f));
+                for (var t = new w(), r = Object.keys(this), n = 0; n < r.length; n++) {
+                  var s = r[n];
+                  t[s] = this[s];
+                }
+                if (((t.hash = e.hash), '' === e.href)) return (t.href = t.format()), t;
+                if (e.slashes && !e.protocol) {
+                  for (var i = Object.keys(e), o = 0; o < i.length; o++) {
+                    var a = i[o];
+                    'protocol' !== a && (t[a] = e[a]);
+                  }
+                  return (
+                    P[t.protocol] && t.hostname && !t.pathname && (t.path = t.pathname = '/'), (t.href = t.format()), t
+                  );
+                }
+                if (e.protocol && e.protocol !== t.protocol) {
+                  if (!P[e.protocol]) {
+                    for (var c = Object.keys(e), l = 0; l < c.length; l++) {
+                      var u = c[l];
+                      t[u] = e[u];
+                    }
+                    return (t.href = t.format()), t;
+                  }
+                  if (((t.protocol = e.protocol), e.host || R[e.protocol])) t.pathname = e.pathname;
+                  else {
+                    for (var p = (e.pathname || '').split('/'); p.length && !(e.host = p.shift()); );
+                    e.host || (e.host = ''),
+                      e.hostname || (e.hostname = ''),
+                      '' !== p[0] && p.unshift(''),
+                      p.length < 2 && p.unshift(''),
+                      (t.pathname = p.join('/'));
+                  }
+                  return (
+                    (t.search = e.search),
+                    (t.query = e.query),
+                    (t.host = e.host || ''),
+                    (t.auth = e.auth),
+                    (t.hostname = e.hostname || e.host),
+                    (t.port = e.port),
+                    (t.pathname || t.search) && ((f = t.pathname || ''), (d = t.search || ''), (t.path = f + d)),
+                    (t.slashes = t.slashes || e.slashes),
+                    (t.href = t.format()),
+                    t
+                  );
+                }
+                var f = t.pathname && '/' === t.pathname.charAt(0),
+                  d = e.host || (e.pathname && '/' === e.pathname.charAt(0)),
+                  f = d || f || (t.host && e.pathname),
+                  h = f,
+                  m = (t.pathname && t.pathname.split('/')) || [],
+                  p = (e.pathname && e.pathname.split('/')) || [],
+                  y = t.protocol && !P[t.protocol];
+                if (
+                  (y &&
+                    ((t.hostname = ''),
+                    (t.port = null),
+                    t.host && ('' === m[0] ? (m[0] = t.host) : m.unshift(t.host)),
+                    (t.host = ''),
+                    e.protocol &&
+                      ((e.hostname = null),
+                      (e.port = null),
+                      e.host && ('' === p[0] ? (p[0] = e.host) : p.unshift(e.host)),
+                      (e.host = null)),
+                    (f = f && ('' === p[0] || '' === m[0]))),
+                  d)
+                )
+                  (t.host = (e.host || '' === e.host ? e : t).host),
+                    (t.hostname = (e.hostname || '' === e.hostname ? e : t).hostname),
+                    (t.search = e.search),
+                    (t.query = e.query),
+                    (m = p);
+                else if (p.length) (m = m || []).pop(), (m = m.concat(p)), (t.search = e.search), (t.query = e.query);
+                else if (!E.isNullOrUndefined(e.search))
+                  return (
+                    y &&
+                      ((t.hostname = t.host = m.shift()),
+                      (j = !!(t.host && 0 < t.host.indexOf('@')) && t.host.split('@')) &&
+                        ((t.auth = j.shift()), (t.host = t.hostname = j.shift()))),
+                    (t.search = e.search),
+                    (t.query = e.query),
+                    (E.isNull(t.pathname) && E.isNull(t.search)) || (t.path = (t.pathname || '') + (t.search || '')),
+                    (t.href = t.format()),
+                    t
+                  );
+                if (!m.length)
+                  return (
+                    (t.pathname = null),
+                    t.search ? (t.path = '/' + t.search) : (t.path = null),
+                    (t.href = t.format()),
+                    t
+                  );
+                for (
+                  var b = m.slice(-1)[0],
+                    d = ((t.host || e.host || 1 < m.length) && ('.' === b || '..' === b)) || '' === b,
+                    g = 0,
+                    v = m.length;
+                  0 <= v;
+                  v--
+                )
+                  '.' === (b = m[v]) ? m.splice(v, 1) : '..' === b ? (m.splice(v, 1), g++) : g && (m.splice(v, 1), g--);
+                if (!f && !h) for (; g--; ) m.unshift('..');
+                !f || '' === m[0] || (m[0] && '/' === m[0].charAt(0)) || m.unshift(''),
+                  d && '/' !== m.join('/').substr(-1) && m.push('');
+                var j,
+                  h = '' === m[0] || (m[0] && '/' === m[0].charAt(0));
+                return (
+                  y &&
+                    ((t.hostname = t.host = !h && m.length ? m.shift() : ''),
+                    (j = !!(t.host && 0 < t.host.indexOf('@')) && t.host.split('@')) &&
+                      ((t.auth = j.shift()), (t.host = t.hostname = j.shift()))),
+                  (f = f || (t.host && m.length)) && !h && m.unshift(''),
+                  m.length ? (t.pathname = m.join('/')) : ((t.pathname = null), (t.path = null)),
+                  (E.isNull(t.pathname) && E.isNull(t.search)) || (t.path = (t.pathname || '') + (t.search || '')),
+                  (t.auth = e.auth || t.auth),
+                  (t.slashes = t.slashes || e.slashes),
+                  (t.href = t.format()),
+                  t
+                );
+              }),
+              (w.prototype.parseHost = function () {
+                var e = this.host,
+                  t = n.exec(e);
+                t && (':' !== (t = t[0]) && (this.port = t.substr(1)), (e = e.substr(0, e.length - t.length))),
+                  e && (this.hostname = e);
+              });
+          },
+          {
+            './util': 447,
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.array.join.js': 276,
+            'core-js/modules/es.array.slice.js': 278,
+            'core-js/modules/es.array.splice.js': 280,
+            'core-js/modules/es.object.keys.js': 289,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.match.js': 303,
+            'core-js/modules/es.string.replace.js': 304,
+            'core-js/modules/es.string.search.js': 305,
+            'core-js/modules/es.string.split.js': 306,
+            'core-js/modules/es.string.trim.js': 307,
+            punycode: 367,
+            querystring: 370
+          }
+        ],
+        447: [
+          function (e, t, r) {
+            'use strict';
+            var n = e('@babel/runtime/helpers/interopRequireDefault')(e('@babel/runtime/helpers/typeof'));
+            t.exports = {
+              isString: function (e) {
+                return 'string' == typeof e;
+              },
+              isObject: function (e) {
+                return 'object' === (0, n.default)(e) && null !== e;
+              },
+              isNull: function (e) {
+                return null === e;
+              },
+              isNullOrUndefined: function (e) {
+                return null == e;
+              }
+            };
+          },
+          { '@babel/runtime/helpers/interopRequireDefault': 77, '@babel/runtime/helpers/typeof': 78 }
+        ],
+        448: [
+          function (e, t, r) {
+            'use strict';
+            e('core-js/modules/es.number.constructor.js'),
+              (r.encodeURIComponent = function (t) {
+                try {
+                  return encodeURIComponent(t);
+                } catch (e) {
+                  return t;
+                }
+              }),
+              (r.escape = e('escape-html')),
+              (r.timestamp = function (e) {
+                var t;
+                return e
+                  ? ('string' == typeof (t = e) && (t = Number(t)), 10 === String(e).length && (t *= 1e3), new Date(t))
+                  : Math.round(Date.now() / 1e3);
+              });
+          },
+          { 'core-js/modules/es.number.constructor.js': 283, 'escape-html': 342 }
+        ],
+        449: [
+          function (e, t, J) {
+            !function (Y, $) {
+              !function () {
+                'use strict';
+                var L = e('@babel/runtime/helpers/interopRequireDefault')(e('@babel/runtime/helpers/typeof')),
+                  B =
+                    (e('core-js/modules/es.string.trim.js'),
+                    e('core-js/modules/es.regexp.exec.js'),
+                    e('core-js/modules/es.string.split.js'),
+                    e('core-js/modules/es.object.to-string.js'),
+                    e('core-js/modules/es.promise.js'),
+                    e('core-js/modules/es.function.name.js'),
+                    e('core-js/modules/es.array.concat.js'),
+                    e('util')),
+                  q = e('url'),
+                  F = e('http'),
+                  U = e('https'),
+                  G = e('debug')('urllib'),
+                  X = e('humanize-ms'),
+                  V = 0,
+                  z = Math.pow(2, 31) - 10,
+                  W = /^https?:\/\//i;
+                function H(e, t) {
+                  return void 0 === e ? t : e;
+                }
+                J.TIMEOUTS = [X('300s'), X('300s')];
+                var K = ['json', 'text'];
+                (J.request = function (r, i, e) {
+                  return (
+                    2 === arguments.length && 'function' == typeof i && ((e = i), (i = null)),
+                    'function' == typeof e
+                      ? J.requestWithCallback(r, i, e)
+                      : new Promise(function (e, t) {
+                          var n, s;
+                          J.requestWithCallback(
+                            r,
+                            i,
+                            ((n = e),
+                            (s = t),
+                            function (e, t, r) {
+                              if (e) return s(e);
+                              n({ data: t, status: r.statusCode, headers: r.headers, res: r });
+                            })
+                          );
+                        })
+                  );
+                }),
+                  (J.requestWithCallback = function (a, c, l) {
+                    if (!a || ('string' != typeof a && 'object' !== (0, L.default)(a)))
+                      throw (
+                        ((t = B.format('expect request url to be a string or a http request options, but got %j', a)),
+                        new Error(t))
+                      );
+                    2 === arguments.length && 'function' == typeof c && ((l = c), (c = null)), z <= V && (V = 0);
+                    var e,
+                      u = ++V,
+                      p =
+                        (((c = c || {}).requestUrls = c.requestUrls || []),
+                        { requestId: u, url: a, args: c, ctx: c.ctx }),
+                      f =
+                        (c.emitter && c.emitter.emit('request', p),
+                        (c.timeout = c.timeout || J.TIMEOUTS),
+                        (c.maxRedirects = c.maxRedirects || 10),
+                        (c.streaming = c.streaming || c.customResponse),
+                        Date.now()),
+                      t = 'string' == typeof a ? (W.test(a) || (a = 'https://' + a), q.parse(a)) : a,
+                      r = (c.type || c.method || t.method || 'GET').toUpperCase(),
+                      n = t.port || 80,
+                      s = F,
+                      d = H(c.agent, J.agent),
+                      M = c.fixJSONCtlChars,
+                      h =
+                        ('https:' === t.protocol && ((s = U), (d = H(c.httpsAgent, J.httpsAgent)), t.port || (n = 443)),
+                        {
+                          host: t.hostname || t.host || 'localhost',
+                          path: t.path || '/',
+                          method: r,
+                          port: n,
+                          agent: d,
+                          headers: c.headers || {},
+                          lookup: c.lookup
+                        }),
+                      n =
+                        (Array.isArray(c.timeout)
+                          ? (h.requestTimeout = c.timeout[c.timeout.length - 1])
+                          : void 0 !== c.timeout && (h.requestTimeout = c.timeout),
+                        c.auth || t.auth),
+                      n = (n && (h.auth = n), c.content || c.data),
+                      i = 'GET' === r || 'HEAD' === r || c.dataAsQueryString,
+                      m =
+                        (c.content ||
+                          (n &&
+                            'string' != typeof n &&
+                            !$.isBuffer(n) &&
+                            (n = i
+                              ? (c.nestedQuerystring ? qs : querystring).stringify(n)
+                              : ((e = h.headers['Content-Type'] || h.headers['content-type']) ||
+                                  ((e =
+                                    'json' === c.contentType
+                                      ? 'application/json'
+                                      : 'application/x-www-form-urlencoded'),
+                                  (h.headers['Content-Type'] = e)),
+                                ('application/json' === ((e = e) ? e.split(';')[0].trim().toLowerCase() : '')
+                                  ? JSON
+                                  : c.nestedQuerystring
+                                  ? qs
+                                  : querystring
+                                ).stringify(n)))),
+                        i && n && ((h.path += (t.query ? '&' : '?') + n), (n = null)),
+                        0),
+                      o =
+                        (n &&
+                          ((e = n.length),
+                          $.isBuffer(n) || (e = $.byteLength(n)),
+                          (m = h.headers['Content-Length'] = e)),
+                        'json' === c.dataType && (h.headers.Accept = 'application/json'),
+                        'function' == typeof c.beforeRequest && c.beforeRequest(h),
+                        null),
+                      y = null,
+                      b = null,
+                      g = !1,
+                      v = !1,
+                      j = 0,
+                      w = -1,
+                      x = !1,
+                      T = '',
+                      k = '',
+                      E = null;
+                    function _() {
+                      o && (clearTimeout(o), (o = null));
+                    }
+                    function S() {
+                      y && (clearTimeout(y), (y = null));
+                    }
+                    function O(e, t, r) {
+                      if ((S(), !l))
+                        return (
+                          console.warn(
+                            '[urllib:warn] [%s] [%s] [worker:%s] %s %s callback twice!!!',
+                            Date(),
+                            u,
+                            Y.pid,
+                            h.method,
+                            a
+                          ),
+                          void (
+                            e &&
+                            console.warn(
+                              '[urllib:warn] [%s] [%s] [worker:%s] %s: %s\nstack: %s',
+                              Date(),
+                              u,
+                              Y.pid,
+                              e.name,
+                              e.message,
+                              e.stack
+                            )
+                          )
+                        );
+                      var n,
+                        s = l,
+                        i = ((l = null), {}),
+                        o = (r && ((w = r.statusCode), (i = r.headers)), Date.now() - f),
+                        o =
+                          (E && (E.contentDownload = o),
+                          G(
+                            '[%sms] done, %s bytes HTTP %s %s %s %s, keepAliveSocket: %s, timing: %j',
+                            o,
+                            j,
+                            w,
+                            h.method,
+                            h.host,
+                            h.path,
+                            v,
+                            E
+                          ),
+                          {
+                            status: w,
+                            statusCode: w,
+                            headers: i,
+                            size: j,
+                            aborted: x,
+                            rt: o,
+                            keepAliveSocket: v,
+                            data: t,
+                            requestUrls: c.requestUrls,
+                            timing: E,
+                            remoteAddress: T,
+                            remotePort: k
+                          });
+                      e &&
+                        ((n = ''),
+                        d &&
+                          'function' == typeof d.getCurrentStatus &&
+                          (n = ', agent status: ' + JSON.stringify(d.getCurrentStatus())),
+                        (e.message +=
+                          ', ' +
+                          h.method +
+                          ' ' +
+                          a +
+                          ' ' +
+                          w +
+                          ' (connected: ' +
+                          g +
+                          ', keepalive socket: ' +
+                          v +
+                          n +
+                          ')\nheaders: ' +
+                          JSON.stringify(i)),
+                        (e.data = t),
+                        (e.path = h.path),
+                        (e.status = w),
+                        (e.headers = i),
+                        (e.res = o)),
+                        s(e, t, c.streaming ? r : o),
+                        c.emitter &&
+                          ((p.url = a),
+                          (p.socket = C && C.connection),
+                          (p.options = h),
+                          (p.size = m),
+                          c.emitter.emit('response', { requestId: u, error: e, ctx: c.ctx, req: p, res: o }));
+                    }
+                    function A(e) {
+                      var t = null;
+                      if (c.followRedirect && statuses.redirect[e.statusCode]) {
+                        c._followRedirectCount = (c._followRedirectCount || 0) + 1;
+                        var r,
+                          n = e.headers.location;
+                        if (n) {
+                          if (!(c._followRedirectCount > c.maxRedirects))
+                            return (
+                              (r = c.formatRedirectUrl ? c.formatRedirectUrl(a, n) : q.resolve(a, n)),
+                              G('Request#%d %s: `redirected` from %s to %s', u, h.path, a, r),
+                              S(),
+                              c.headers && c.headers.Host && W.test(n) && (c.headers.Host = null),
+                              (n = l),
+                              (l = null),
+                              J.requestWithCallback(r, c, n),
+                              { redirect: !0, error: null }
+                            );
+                          (t = new Error('Exceeded maxRedirects. Probably stuck in a redirect loop ' + a)).name =
+                            'MaxRedirectError';
+                        } else
+                          (t = new Error(
+                            'Got statusCode ' + e.statusCode + ' but cannot resolve next location from headers'
+                          )).name = 'FollowRedirectError';
+                      }
+                      return { redirect: !1, error: t };
+                    }
+                    c.timing &&
+                      (E = { queuing: 0, dnslookup: 0, connected: 0, requestSent: 0, waiting: 0, contentDownload: 0 }),
+                      !c.gzip ||
+                        h.headers['Accept-Encoding'] ||
+                        h.headers['accept-encoding'] ||
+                        (h.headers['Accept-Encoding'] = 'gzip');
+                    var D,
+                      I,
+                      C,
+                      N = c.writeStream;
+                    function R() {
+                      G('Response timer ticking, timeout: %d', I),
+                        (y = setTimeout(function () {
+                          y = null;
+                          var e = 'Response timeout for ' + I + 'ms';
+                          ((b = new Error(e)).name = 'ResponseTimeoutError'),
+                            (b.requestId = u),
+                            G('ResponseTimeout: Request#%d %s %s: %s, connected: %s', u, a, b.name, e, g),
+                            P();
+                        }, I));
+                    }
+                    G('Request#%d %s %s with headers %j, options.path: %s', u, r, a, h.headers, h.path),
+                      c.requestUrls.push(a),
+                      Array.isArray(c.timeout)
+                        ? ((D = X(c.timeout[0])), (I = X(c.timeout[1])))
+                        : (D = I = X(c.timeout)),
+                      G('ConnectTimeout: %d, ResponseTimeout: %d', D, I),
+                      (h.mode = c.mode || '');
+                    try {
+                      C = s.request(h, function (s) {
+                        var e;
+                        if (
+                          (E && (E.waiting = Date.now() - f),
+                          G(
+                            'Request#%d %s `req response` event emit: status %d, headers: %j',
+                            u,
+                            a,
+                            s.statusCode,
+                            s.headers
+                          ),
+                          c.streaming)
+                        )
+                          return (e = A(s)).redirect
+                            ? void s.resume()
+                            : e.error
+                            ? (s.resume(), O(e.error, null, s))
+                            : O(null, null, s);
+                        if (
+                          (s.on('close', function () {
+                            G('Request#%d %s: `res close` event emit, total size %d', u, a, j);
+                          }),
+                          s.on('error', function () {
+                            G('Request#%d %s: `res error` event emit, total size %d', u, a, j);
+                          }),
+                          s.on('aborted', function () {
+                            (x = !0), G('Request#%d %s: `res aborted` event emit, total size %d', u, a, j);
+                          }),
+                          N)
+                        )
+                          return (e = A(s)).redirect
+                            ? void s.resume()
+                            : e.error
+                            ? (s.resume(), N.end(), O(e.error, null, s))
+                            : (!1 === c.consumeWriteStream
+                                ? s.on('end', O.bind(null, null, null, s))
+                                : N.on('close', function () {
+                                    G('Request#%d %s: writeStream close event emitted', u, a), O(b || null, null, s);
+                                  }),
+                              s.pipe(N));
+                        var t = [];
+                        s.on('data', function (e) {
+                          G('Request#%d %s: `res data` event emit, size %d', u, a, e.length),
+                            (j += e.length),
+                            t.push(e);
+                        }),
+                          s.on('end', function () {
+                            var e,
+                              n = $.concat(t, j);
+                            return (
+                              G('Request#%d %s: `res end` event emit, total size %d, _dumped: %s', u, a, j, s._dumped),
+                              b
+                                ? O(b, n, s)
+                                : (e = A(s)).error
+                                ? O(e.error, n, s)
+                                : void (
+                                    e.redirect ||
+                                    (function (e, t, r) {
+                                      if (e) return O(e, n, s);
+                                      if (!r && 0 <= K.indexOf(c.dataType)) {
+                                        try {
+                                          t = decodeBodyByCharset(t, s);
+                                        } catch (e) {
+                                          return G('decodeBodyByCharset error: %s', e), O(null, t, s);
+                                        }
+                                        'json' === c.dataType &&
+                                          (0 === j
+                                            ? (t = null)
+                                            : (r = parseJSON(t, M)).error
+                                            ? (e = r.error)
+                                            : (t = r.data));
+                                      }
+                                      x &&
+                                        G(
+                                          'Request#%d %s: Remote socket was terminated before `response.end()` was called',
+                                          u,
+                                          a
+                                        ),
+                                        O(e, t, s);
+                                    })(null, n, s.headers['content-encoding'])
+                                  )
+                            );
+                          });
+                      });
+                    } catch (e) {
+                      return O(e);
+                    }
+                    function P() {
+                      G('Request#%d %s abort, connected: %s', u, a, g),
+                        C.socket || ((b.noSocket = !0), O(b)),
+                        C.abort();
+                    }
+                    return (
+                      'undefined' == typeof window
+                        ? (G('Connect timer ticking, timeout: %d', D),
+                          (o = setTimeout(function () {
+                            (o = null), -1 === w && (w = -2);
+                            var e = 'Connect timeout for ' + D + 'ms',
+                              t = 'ConnectionTimeoutError';
+                            C.socket || ((t = 'SocketAssignTimeoutError'), (e += ', working sockets is full')),
+                              ((b = new Error(e)).name = t),
+                              (b.requestId = u),
+                              G('ConnectTimeout: Request#%d %s %s: %s, connected: %s', u, a, b.name, e, g),
+                              P();
+                          }, D)))
+                        : C.on('requestTimeout', function () {
+                            -1 === w && (w = -2);
+                            ((b = new Error('Connect timeout for ' + D + 'ms')).name = 'ConnectionTimeoutError'),
+                              (b.requestId = u),
+                              P();
+                          }),
+                      E &&
+                        C.on('finish', function () {
+                          E.requestSent = Date.now() - f;
+                        }),
+                      C.once('socket', function (e) {
+                        E && (E.queuing = Date.now() - f);
+                        var t = e.readyState;
+                        if ('opening' === t)
+                          return (
+                            e.once('lookup', function (e, t, r) {
+                              G('Request#%d %s lookup: %s, %s, %s', u, a, e, t, r),
+                                E && (E.dnslookup = Date.now() - f),
+                                t && (T = t);
+                            }),
+                            void e.once('connect', function () {
+                              E && (E.connected = Date.now() - f),
+                                _(),
+                                R(),
+                                G('Request#%d %s new socket connected', u, a),
+                                (g = !0),
+                                (T = T || e.remoteAddress),
+                                (k = e.remotePort);
+                            })
+                          );
+                        G('Request#%d %s reuse socket connected, readyState: %s', u, a, t),
+                          (v = g = !0),
+                          (T = T || e.remoteAddress),
+                          (k = e.remotePort),
+                          _(),
+                          R();
+                      }),
+                      C.on('error', function (e) {
+                        ('Error' !== e.name && 'TypeError' !== e.name) ||
+                          (e.name = g ? 'ResponseError' : 'RequestError'),
+                          (e.message += ' (req "error")'),
+                          G('Request#%d %s `req error` event emit, %s: %s', u, a, e.name, e.message),
+                          O(b || e);
+                      }),
+                      N &&
+                        N.once('error', function (e) {
+                          (e.message += ' (writeStream "error")'),
+                            G('Request#%d %s `writeStream error` event emit, %s: %s', u, a, (b = e).name, e.message),
+                            P();
+                        }),
+                      c.stream
+                        ? (c.stream.pipe(C),
+                          c.stream.once('error', function (e) {
+                            (e.message += ' (stream "error")'),
+                              G('Request#%d %s `readStream error` event emit, %s: %s', u, a, (b = e).name, e.message),
+                              P();
+                          }))
+                        : C.end(n),
+                      (C.requestId = u),
+                      C
+                    );
+                  });
+              }.call(this);
+            }.call(this, e('_process'), e('buffer').Buffer);
+          },
+          {
+            '@babel/runtime/helpers/interopRequireDefault': 77,
+            '@babel/runtime/helpers/typeof': 78,
+            _process: 441,
+            buffer: 89,
+            'core-js/modules/es.array.concat.js': 269,
+            'core-js/modules/es.function.name.js': 281,
+            'core-js/modules/es.object.to-string.js': 290,
+            'core-js/modules/es.promise.js': 294,
+            'core-js/modules/es.regexp.exec.js': 299,
+            'core-js/modules/es.string.split.js': 306,
+            'core-js/modules/es.string.trim.js': 307,
+            debug: 439,
+            http: 442,
+            https: 344,
+            'humanize-ms': 345,
+            url: 446,
+            util: 394
+          }
+        ]
+      },
+      {},
+      [1]
+    )(1);
+  });
+})(window);

File diff suppressed because it is too large
+ 1 - 0
public/assets/v1/common/js/axios.min.js


+ 8 - 0
public/assets/v1/common/js/cookie.min.js

@@ -0,0 +1,8 @@
+/**
+ * Minified by jsDelivr using Terser v3.14.1.
+ * Original file: /npm/js-cookie@2.2.1/src/js.cookie.js
+ * 
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
+ */
+!function(e){var n;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var t=window.Cookies,o=window.Cookies=e();o.noConflict=function(){return window.Cookies=t,o}}}(function(){function e(){for(var e=0,n={};e<arguments.length;e++){var t=arguments[e];for(var o in t)n[o]=t[o]}return n}function n(e){return e.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)}return function t(o){function r(){}function i(n,t,i){if("undefined"!=typeof document){"number"==typeof(i=e({path:"/"},r.defaults,i)).expires&&(i.expires=new Date(1*new Date+864e5*i.expires)),i.expires=i.expires?i.expires.toUTCString():"";try{var c=JSON.stringify(t);/^[\{\[]/.test(c)&&(t=c)}catch(e){}t=o.write?o.write(t,n):encodeURIComponent(String(t)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=encodeURIComponent(String(n)).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var f="";for(var u in i)i[u]&&(f+="; "+u,!0!==i[u]&&(f+="="+i[u].split(";")[0]));return document.cookie=n+"="+t+f}}function c(e,t){if("undefined"!=typeof document){for(var r={},i=document.cookie?document.cookie.split("; "):[],c=0;c<i.length;c++){var f=i[c].split("="),u=f.slice(1).join("=");t||'"'!==u.charAt(0)||(u=u.slice(1,-1));try{var a=n(f[0]);if(u=(o.read||o)(u,a)||n(u),t)try{u=JSON.parse(u)}catch(e){}if(r[a]=u,e===a)break}catch(e){}}return e?r[e]:r}}return r.set=i,r.get=function(e){return c(e,!1)},r.getJSON=function(e){return c(e,!0)},r.remove=function(n,t){i(n,"",e(t,{expires:-1}))},r.defaults={},r.withConverter=t,r}(function(){})});
+//# sourceMappingURL=/sm/b0ce608ffc029736e9ac80a8dd6a7db2da8e1d45d2dcfc92043deb2214aa30d8.map

File diff suppressed because it is too large
+ 1 - 0
public/assets/v1/common/js/jquery-3.6.0.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/js/particles.min.js


File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/js/pinyin-pro.js


File diff suppressed because it is too large
+ 5 - 0
public/assets/v1/common/js/vue.min.js


+ 234 - 0
public/assets/v1/common/lib/captcha/vue-puzzle-vcode.css

@@ -0,0 +1,234 @@
+.vue-puzzle-vcode {
+    position: fixed;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    background-color: rgba(0, 0, 0, 0.3);
+    z-index: 999;
+    opacity: 0;
+    pointer-events: none;
+    transition: opacity 200ms;
+}
+.vue-puzzle-vcode.show_{
+    opacity: 1;
+    pointer-events: auto;
+}
+.vue-auth-box_ {
+    position: absolute;
+    top: 40%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    padding: 20px;
+    background: #fff;
+    user-select: none;
+    border-radius: 3px;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+}
+.vue-auth-box_ .auth-body_ {
+    position: relative;
+    overflow: hidden;
+    border-radius: 3px;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    background-color: rgba(0, 0, 0, 0.8);
+    z-index: 20;
+    opacity: 1;
+    transition: opacity 200ms;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.vue-auth-box_ .auth-body_ .loading-box_.hide_ {
+    opacity: 0;
+    pointer-events: none;
+}
+.vue-auth-box_ .auth-body_ .loading-box_.hide_ .loading-gif_ span{
+    animation-play-state: paused;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ {
+    flex: none;
+    height: 5px;
+    line-height: 0;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ @keyframes load{
+   0% {
+       opacity: 1;
+       transform: scale(1.3);
+   }
+   100% {
+       opacity: 0.2;
+       transform: scale(0.3);
+   }
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span {
+    display: inline-block;
+    width: 5px;
+    height: 100%;
+    margin-left: 2px;
+    border-radius: 50%;
+    background-color: #888;
+    animation: load 1.04s ease infinite;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span:nth-child(1) {
+    margin-left: 0;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span:nth-child(2) {
+    animation-delay: 0.13s;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span:nth-child(3) {
+    animation-delay: 0.26s;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span:nth-child(4) {
+    animation-delay: 0.39s;
+}
+.vue-auth-box_ .auth-body_ .loading-box_ .loading-gif_ span:nth-child(5) {
+    animation-delay: 0.52s;
+}
+.vue-auth-box_ .auth-body_ .info-box_ {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 24px;
+    line-height: 24px;
+    text-align: center;
+    overflow: hidden;
+    font-size: 13px;
+    background-color: #83ce3f;
+    opacity: 0;
+    transform: translateY(24px);
+    transition: all 200ms;
+    color: #fff;
+    z-index: 10;
+}
+.vue-auth-box_ .auth-body_ .info-box_.show {
+    opacity: 0.95;
+    transform: translateY(0);
+}
+.vue-auth-box_ .auth-body_ .info-box_.fail {
+    background-color: #ce594b;
+}
+.vue-auth-box_ .auth-body_ .auth-canvas2_ {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 60px;
+    height: 100%;
+    z-index: 2;
+}
+.vue-auth-box_ .auth-body_ .auth-canvas3_ {
+    position: absolute;
+    top: 0;
+    left: 0;
+    opacity: 0;
+    transition: opacity 600ms;
+    z-index: 3;
+}
+.vue-auth-box_ .auth-body_ .auth-canvas3_.show {
+    opacity: 1;
+}
+.vue-auth-box_ .auth-body_ .flash_ {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 30px;
+    height: 100%;
+    background-color: rgba(255, 255, 255, 0.1);
+    z-index: 3;
+}
+.vue-auth-box_ .auth-body_ .flash_.show {
+    transition: transform 600ms;
+}
+.vue-auth-box_ .auth-body_ .reset_ {
+    position: absolute;
+    top: 2px;
+    right: 2px;
+    width: 25px;
+    height: auto;
+    z-index: 12;
+    cursor: pointer;
+    transition: transform 200ms;
+    transform: rotate(0deg);
+    font-size: 25px !important;
+    color: #fff !important;
+    text-shadow: 1px 1px 3px #5a5a5a !important;
+}
+.vue-auth-box_ .auth-body_ .reset_:hover {
+    transform: rotate(-90deg);
+}
+.vue-auth-box_ .auth-control_ .range-box {
+    position: relative;
+    width: 100%;
+    background-color: #eef1f8;
+    margin-top: 20px;
+    border-radius: 3px;
+    box-shadow: 0 0 8px rgba(240, 240, 240, 0.6) inset;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-text {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 14px;
+    color: #b7bcd1;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    text-align: center;
+    width: 100%;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider {
+    position: absolute;
+    height: 100%;
+    width: 50px;
+    background-color: rgba(106, 160, 255, 0.8);
+    border-radius: 3px;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn {
+    position: absolute;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    right: 0;
+    width: 50px;
+    height: 100%;
+    background-color: #fff;
+    border-radius: 3px;
+    box-shadow: 0 0 4px #ccc;
+    cursor: pointer;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn > div {
+    width: 0;
+    height: 40%;
+    transition: all 200ms;
+    border: solid 1px #6aa0ff;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn > div:nth-child(2) {
+    margin: 0 4px;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn:hover > div:first-child,.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn.isDown > div:first-child{
+    border: solid 4px transparent;
+    height: 0;
+    border-right-color: #6aa0ff;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn:hover > div:nth-child(2),.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn.isDown > div:nth-child(2){
+    border-width: 3px;
+    height: 0;
+    border-radius: 3px;
+    margin: 0 6px;
+    border-right-color: #6aa0ff;
+}
+.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn:hover > div:nth-child(3),.vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn.isDown > div:nth-child(3){
+    border: solid 4px transparent;
+    height: 0;
+    border-left-color: #6aa0ff;
+}
+.vue-puzzle-overflow {
+    overflow: hidden !important;
+}

+ 582 - 0
public/assets/v1/common/lib/captcha/vue-puzzle-vcode.js

@@ -0,0 +1,582 @@
+// 滑动校验组件
+Vue.component('vue-puzzle-vcode', {
+    props: {
+        canvasWidth: { type: Number, default: 310 }, // 主canvas的宽
+        canvasHeight: { type: Number, default: 160 }, // 主canvas的高
+        // 是否出现,由父级控制
+        show: { type: Boolean, default: false },
+        puzzleScale: { type: Number, default: 1 }, // 拼图块的大小缩放比例
+        sliderSize: { type: Number, default: 50 }, // 滑块的大小
+        range: { type: Number, default: 10 }, // 允许的偏差值
+        // 所有的背景图片
+        imgs: {
+            type: Array
+        },
+        successText: {
+            type: String,
+            default: "验证通过!"
+        },
+        failText: {
+            type: String,
+            default: "验证失败,请重试"
+        },
+        sliderText: {
+            type: String,
+            default: "拖动滑块完成拼图"
+        }
+    },
+    data() {
+        return {
+            mouseDown: false, // 鼠标是否在按钮上按下
+            startWidth: 50, // 鼠标点下去时父级的width
+            startX: 0, // 鼠标按下时的X
+            newX: 0, // 鼠标当前的偏移X
+            pinX: 0, // 拼图的起始X
+            pinY: 0, // 拼图的起始Y
+            loading: false, // 是否正在加在中,主要是等图片onload
+            isCanSlide: false, // 是否可以拉动滑动条
+            error: false, // 图片加在失败会出现这个,提示用户手动刷新
+            infoBoxShow: false, // 提示信息是否出现
+            infoText: "", // 提示等信息
+            infoBoxFail: false, // 是否验证失败
+            timer1: null, // setTimout1
+            closeDown: false, // 为了解决Mac上的click BUG
+            isSuccess: false, // 验证成功
+            imgIndex: -1, // 用于自定义图片时不会随机到重复的图片
+            isSubmting: false, // 是否正在判定,主要用于判定中不能点击重置按钮
+            resetSvg: "el-icon-refresh",
+        };
+    },
+    template: '<div :class="[\'vue-puzzle-vcode\', { show_: show }]"\n' +
+        '       @mousedown="onCloseMouseDown"\n' +
+        '       @mouseup="onCloseMouseUp"\n' +
+        '       @touchstart="onCloseMouseDown"\n' +
+        '       @touchend="onCloseMouseUp">\n' +
+        '    <div class="vue-auth-box_"\n' +
+        '         @mousedown.stop\n' +
+        '         @touchstart.stop>\n' +
+        '      <div class="auth-body_"\n' +
+        '           :style="`height: ${canvasHeight}px`">\n' +
+        '        <!-- 主图,有缺口 -->\n' +
+        '        <canvas ref="canvas1"\n' +
+        '                :width="canvasWidth"\n' +
+        '                :height="canvasHeight"\n' +
+        '                :style="`width:${canvasWidth}px;height:${canvasHeight}px`" />\n' +
+        '        <!-- 成功后显示的完整图 -->\n' +
+        '        <canvas ref="canvas3"\n' +
+        '                :class="[\'auth-canvas3_\', { show: isSuccess }]"\n' +
+        '                :width="canvasWidth"\n' +
+        '                :height="canvasHeight"\n' +
+        '                :style="`width:${canvasWidth}px;height:${canvasHeight}px`" />\n' +
+        '        <!-- 小图 -->\n' +
+        '        <canvas :width="puzzleBaseSize"\n' +
+        '                class="auth-canvas2_"\n' +
+        '                :height="canvasHeight"\n' +
+        '                ref="canvas2"\n' +
+        '                :style="\n' +
+        '            `width:${puzzleBaseSize}px;height:${canvasHeight}px;transform:translateX(${styleWidth -\n' +
+        '              sliderBaseSize -\n' +
+        '              (puzzleBaseSize - sliderBaseSize) *\n' +
+        '                ((styleWidth - sliderBaseSize) /\n' +
+        '                  (canvasWidth - sliderBaseSize))}px)`\n' +
+        '          " />\n' +
+        '        <div :class="[\'loading-box_\', { hide_: !loading }]">\n' +
+        '          <div class="loading-gif_">\n' +
+        '            <span></span>\n' +
+        '            <span></span>\n' +
+        '            <span></span>\n' +
+        '            <span></span>\n' +
+        '            <span></span>\n' +
+        '          </div>\n' +
+        '        </div>\n' +
+        '        <div :class="[\'info-box_\', { show: infoBoxShow }, { fail: infoBoxFail }]">\n' +
+        '          {{ infoText }}\n' +
+        '        </div>\n' +
+        '        <div :class="[\'flash_\', { show: isSuccess }]"\n' +
+        '             :style="\n' +
+        '            `transform: translateX(${\n' +
+        '              isSuccess\n' +
+        '                ? `${canvasWidth + canvasHeight * 0.578}px`\n' +
+        '                : `-${canvasHeight * 0.578}px`\n' +
+        '            }) skew(-30deg, 0);`\n' +
+        '          "></div>\n' +
+        '        <i class="reset_" :class="resetSvg" @click="reset" />\n' +
+        '      </div>\n' +
+        '      <div class="auth-control_">\n' +
+        '        <div class="range-box"\n' +
+        '             :style="`height:${sliderBaseSize}px`">\n' +
+        '          <div class="range-text">{{ sliderText }}</div>\n' +
+        '          <div class="range-slider"\n' +
+        '               ref="range-slider"\n' +
+        '               :style="`width:${styleWidth}px`">\n' +
+        '            <div :class="[\'range-btn\', { isDown: mouseDown }]"\n' +
+        '                 :style="`width:${sliderBaseSize}px`"\n' +
+        '                 @mousedown="onRangeMouseDown($event)"\n' +
+        '                 @touchstart="onRangeMouseDown($event)">\n' +
+        '              <div></div>\n' +
+        '              <div></div>\n' +
+        '              <div></div>\n' +
+        '            </div>\n' +
+        '          </div>\n' +
+        '        </div>\n' +
+        '      </div>\n' +
+        '    </div>\n' +
+        '  </div>',
+    mounted: function () {
+        document.body.appendChild(this.$el);
+        document.addEventListener("mousemove", this.onRangeMouseMove, false);
+        document.addEventListener("mouseup", this.onRangeMouseUp, false);
+
+        document.addEventListener("touchmove", this.onRangeMouseMove, {
+            passive: false
+        });
+        document.addEventListener("touchend", this.onRangeMouseUp, false);
+        if (this.show) {
+            document.body.classList.add("vue-puzzle-overflow");
+            this.reset();
+        }
+    },
+    beforeDestroy() {
+        clearTimeout(this.timer1);
+        document.body.removeChild(this.$el);
+        document.removeEventListener("mousemove", this.onRangeMouseMove, false);
+        document.removeEventListener("mouseup", this.onRangeMouseUp, false);
+
+        document.removeEventListener("touchmove", this.onRangeMouseMove, {
+            passive: false
+        });
+        document.removeEventListener("touchend", this.onRangeMouseUp, false);
+    },
+
+    /** 监听 **/
+    watch: {
+        show(newV) {
+            // 每次出现都应该重新初始化
+            if (newV) {
+                document.body.classList.add("vue-puzzle-overflow");
+                this.reset();
+            } else {
+                this.isSubmting = false;
+                this.isSuccess = false;
+                this.infoBoxShow = false;
+                document.body.classList.remove("vue-puzzle-overflow");
+            }
+        }
+    },
+    /** 计算属性 **/
+    computed: {
+        // styleWidth是底部用户操作的滑块的父级,就是轨道在鼠标的作用下应该具有的宽度
+        styleWidth() {
+            const w = this.startWidth + this.newX - this.startX;
+            return w < this.sliderBaseSize
+                ? this.sliderBaseSize
+                : w > this.canvasWidth
+                    ? this.canvasWidth
+                    : w;
+        },
+        // 图中拼图块的60 * 用户设定的缩放比例计算之后的值 0.2~2
+        puzzleBaseSize() {
+            return Math.round(
+                Math.max(Math.min(this.puzzleScale, 2), 0.2) * 52.5 + 6
+            );
+        },
+        // 处理一下sliderSize,弄成整数,以免计算有偏差
+        sliderBaseSize() {
+            return Math.max(
+                Math.min(
+                    Math.round(this.sliderSize),
+                    Math.round(this.canvasWidth * 0.5)
+                ),
+                10
+            );
+        }
+    },
+
+    /** 方法 **/
+    methods: {
+        // 关闭
+        onClose() {
+            if (!this.mouseDown && !this.isSubmting) {
+                clearTimeout(this.timer1);
+                this.$emit("close");
+            }
+        },
+        onCloseMouseDown() {
+            this.closeDown = true;
+        },
+        onCloseMouseUp() {
+            if (this.closeDown) {
+                this.onClose();
+            }
+            this.closeDown = false;
+        },
+        // 鼠标按下准备拖动
+        onRangeMouseDown(e) {
+            if (this.isCanSlide) {
+                this.mouseDown = true;
+                this.startWidth = this.$refs["range-slider"].clientWidth;
+                this.newX = e.clientX || e.changedTouches[0].clientX;
+                this.startX = e.clientX || e.changedTouches[0].clientX;
+            }
+        },
+        // 鼠标移动
+        onRangeMouseMove(e) {
+            if (this.mouseDown) {
+                e.preventDefault();
+                this.newX = e.clientX || e.changedTouches[0].clientX;
+            }
+        },
+        // 鼠标抬起
+        onRangeMouseUp() {
+            if (this.mouseDown) {
+                this.mouseDown = false;
+                this.submit();
+            }
+        },
+        /**
+         * 开始进行
+         * @param withCanvas 是否强制使用canvas随机作图
+         */
+        init(withCanvas) {
+            // 防止重复加载导致的渲染错误
+            if(this.loading && !withCanvas){
+                return;
+            }
+            this.loading = true;
+            this.isCanSlide = false;
+            const c = this.$refs.canvas1;
+            const c2 = this.$refs.canvas2;
+            const c3 = this.$refs.canvas3;
+            const ctx = c.getContext("2d");
+            const ctx2 = c2.getContext("2d");
+            const ctx3 = c3.getContext("2d");
+            const isFirefox = navigator.userAgent.indexOf("Firefox") >= 0 && navigator.userAgent.indexOf("Windows") >= 0; // 是windows版火狐
+            const img = document.createElement("img");
+            ctx.fillStyle = "rgba(255,255,255,1)";
+            ctx3.fillStyle = "rgba(255,255,255,1)";
+            ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+            ctx2.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+
+            // 取一个随机坐标,作为拼图块的位置
+            this.pinX = this.getRandom(this.puzzleBaseSize,this.canvasWidth - this.puzzleBaseSize - 20); // 留20的边距
+            this.pinY = this.getRandom(20,this.canvasHeight - this.puzzleBaseSize - 20); // 主图高度 - 拼图块自身高度 - 20边距
+            img.crossOrigin = "anonymous"; // 匿名,想要获取跨域的图片
+            img.onload = () => {
+                const [x, y, w, h] = this.makeImgSize(img);
+                ctx.save();
+                // 先画小图
+                this.paintBrick(ctx);
+                ctx.closePath();
+                if(!isFirefox){
+                    ctx.shadowOffsetX = 0;
+                    ctx.shadowOffsetY = 0;
+                    ctx.shadowColor = "#000";
+                    ctx.shadowBlur = 3;
+                    ctx.fill();
+                    ctx.clip();
+                } else {
+                    ctx.clip();
+                    ctx.save();
+                    ctx.shadowOffsetX = 0;
+                    ctx.shadowOffsetY = 0;
+                    ctx.shadowColor = "#000";
+                    ctx.shadowBlur = 3;
+                    ctx.fill();
+                    ctx.restore();
+                }
+
+                ctx.drawImage(img, x, y, w, h);
+                ctx3.fillRect(0,0,this.canvasWidth,this.canvasHeight);
+                ctx3.drawImage(img, x, y, w, h);
+
+                // 设置小图的内阴影
+                ctx.globalCompositeOperation = "source-atop";
+
+                this.paintBrick(ctx);
+
+                ctx.arc(
+                    this.pinX + Math.ceil(this.puzzleBaseSize / 2),
+                    this.pinY + Math.ceil(this.puzzleBaseSize / 2),
+                    this.puzzleBaseSize * 1.2,
+                    0,
+                    Math.PI * 2,
+                    true
+                );
+                ctx.closePath();
+                ctx.shadowColor = "rgba(255, 255, 255, .8)";
+                ctx.shadowOffsetX = -1;
+                ctx.shadowOffsetY = -1;
+                ctx.shadowBlur = Math.min(Math.ceil(8 * this.puzzleScale), 12);
+                ctx.fillStyle = "#ffffaa";
+                ctx.fill();
+
+                // 将小图赋值给ctx2
+                const imgData = ctx.getImageData(
+                    this.pinX - 3, // 为了阴影 是从-3px开始截取,判定的时候要+3px
+                    this.pinY - 20,
+                    this.pinX + this.puzzleBaseSize + 5,
+                    this.pinY + this.puzzleBaseSize + 5
+                );
+                ctx2.putImageData(imgData, 0, this.pinY - 20);
+
+                // ctx2.drawImage(c, this.pinX - 3,this.pinY - 20,this.pinX + this.puzzleBaseSize + 5,this.pinY + this.puzzleBaseSize + 5,
+                // 0, this.pinY - 20, this.pinX + this.puzzleBaseSize + 5, this.pinY + this.puzzleBaseSize + 5);
+
+                // 清理
+                ctx.restore();
+                ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+
+                // 画缺口
+                ctx.save();
+                this.paintBrick(ctx);
+                ctx.globalAlpha = 0.8;
+                ctx.fillStyle = "#ffffff";
+                ctx.fill();
+                ctx.restore();
+
+                // 画缺口的内阴影
+                ctx.save();
+                ctx.globalCompositeOperation = "source-atop";
+                this.paintBrick(ctx);
+                ctx.arc(
+                    this.pinX + Math.ceil(this.puzzleBaseSize / 2),
+                    this.pinY + Math.ceil(this.puzzleBaseSize / 2),
+                    this.puzzleBaseSize * 1.2,
+                    0,
+                    Math.PI * 2,
+                    true
+                );
+                ctx.shadowColor = "#000";
+                ctx.shadowOffsetX = 2;
+                ctx.shadowOffsetY = 2;
+                ctx.shadowBlur = 16;
+                ctx.fill();
+                ctx.restore();
+
+                // 画整体背景图
+                ctx.save();
+                ctx.globalCompositeOperation = "destination-over";
+                ctx.drawImage(img, x, y, w, h);
+                ctx.restore();
+
+                this.loading = false;
+                this.isCanSlide = true;
+            };
+            img.onerror = () => {
+                this.init(true); // 如果图片加载错误就重新来,并强制用canvas随机作图
+            };
+
+            if (!withCanvas && this.imgs && this.imgs.length) {
+                let randomNum = this.getRandom(0, this.imgs.length - 1);
+                if (randomNum === this.imgIndex) {
+                    if (randomNum === this.imgs.length - 1) {
+                        randomNum = 0;
+                    } else {
+                        randomNum++;
+                    }
+                }
+                this.imgIndex = randomNum;
+                img.src = this.imgs[randomNum];
+            } else {
+                img.src = this.makeImgWithCanvas();
+            }
+        },
+        // 工具 - 范围随机数
+        getRandom(min, max) {
+            return Math.ceil(Math.random() * (max - min) + min);
+        },
+        // 工具 - 设置图片尺寸cover方式贴合canvas尺寸 w/h
+        makeImgSize(img) {
+            const imgScale = img.width / img.height;
+            const canvasScale = this.canvasWidth / this.canvasHeight;
+            let x = 0,
+                y = 0,
+                w = 0,
+                h = 0;
+            if (imgScale > canvasScale) {
+                h = this.canvasHeight;
+                w = imgScale * h;
+                y = 0;
+                x = (this.canvasWidth - w) / 2;
+            } else {
+                w = this.canvasWidth;
+                h = w / imgScale;
+                x = 0;
+                y = (this.canvasHeight - h) / 2;
+            }
+            return [x, y, w, h];
+        },
+        // 绘制拼图块的路径
+        paintBrick(ctx) {
+            const moveL = Math.ceil(15 * this.puzzleScale); // 直线移动的基础距离
+            ctx.beginPath();
+            ctx.moveTo(this.pinX, this.pinY);
+            ctx.lineTo(this.pinX + moveL, this.pinY);
+            ctx.arcTo(
+                this.pinX + moveL,
+                this.pinY - moveL / 2,
+                this.pinX + moveL + moveL / 2,
+                this.pinY - moveL / 2,
+                moveL / 2
+            );
+            ctx.arcTo(
+                this.pinX + moveL + moveL,
+                this.pinY - moveL / 2,
+                this.pinX + moveL + moveL,
+                this.pinY,
+                moveL / 2
+            );
+            ctx.lineTo(this.pinX + moveL + moveL + moveL, this.pinY);
+            ctx.lineTo(this.pinX + moveL + moveL + moveL, this.pinY + moveL);
+            ctx.arcTo(
+                this.pinX + moveL + moveL + moveL + moveL / 2,
+                this.pinY + moveL,
+                this.pinX + moveL + moveL + moveL + moveL / 2,
+                this.pinY + moveL + moveL / 2,
+                moveL / 2
+            );
+            ctx.arcTo(
+                this.pinX + moveL + moveL + moveL + moveL / 2,
+                this.pinY + moveL + moveL,
+                this.pinX + moveL + moveL + moveL,
+                this.pinY + moveL + moveL,
+                moveL / 2
+            );
+            ctx.lineTo(
+                this.pinX + moveL + moveL + moveL,
+                this.pinY + moveL + moveL + moveL
+            );
+            ctx.lineTo(this.pinX, this.pinY + moveL + moveL + moveL);
+            ctx.lineTo(this.pinX, this.pinY + moveL + moveL);
+
+            ctx.arcTo(
+                this.pinX + moveL / 2,
+                this.pinY + moveL + moveL,
+                this.pinX + moveL / 2,
+                this.pinY + moveL + moveL / 2,
+                moveL / 2
+            );
+            ctx.arcTo(
+                this.pinX + moveL / 2,
+                this.pinY + moveL,
+                this.pinX,
+                this.pinY + moveL,
+                moveL / 2
+            );
+            ctx.lineTo(this.pinX, this.pinY);
+        },
+        // 用canvas随机生成图片
+        makeImgWithCanvas() {
+            const canvas = document.createElement("canvas");
+            const ctx = canvas.getContext("2d");
+            canvas.width = this.canvasWidth;
+            canvas.height = this.canvasHeight;
+            ctx.fillStyle = `rgb(${this.getRandom(100, 255)},${this.getRandom(
+                100,
+                255
+            )},${this.getRandom(100, 255)})`;
+            ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
+            // 随机画10个图形
+            for (let i = 0; i < 12; i++) {
+                ctx.fillStyle = `rgb(${this.getRandom(100, 255)},${this.getRandom(
+                    100,
+                    255
+                )},${this.getRandom(100, 255)})`;
+                ctx.strokeStyle = `rgb(${this.getRandom(100, 255)},${this.getRandom(
+                    100,
+                    255
+                )},${this.getRandom(100, 255)})`;
+
+                if (this.getRandom(0, 2) > 1) {
+                    // 矩形
+                    ctx.save();
+                    ctx.rotate((this.getRandom(-90, 90) * Math.PI) / 180);
+                    ctx.fillRect(
+                        this.getRandom(-20, canvas.width - 20),
+                        this.getRandom(-20, canvas.height - 20),
+                        this.getRandom(10, canvas.width / 2 + 10),
+                        this.getRandom(10, canvas.height / 2 + 10)
+                    );
+                    ctx.restore();
+                } else {
+                    // 圆
+                    ctx.beginPath();
+                    const ran = this.getRandom(-Math.PI, Math.PI);
+                    ctx.arc(
+                        this.getRandom(0, canvas.width),
+                        this.getRandom(0, canvas.height),
+                        this.getRandom(10, canvas.height / 2 + 10),
+                        ran,
+                        ran + Math.PI * 1.5
+                    );
+                    ctx.closePath();
+                    ctx.fill();
+                }
+            }
+            return canvas.toDataURL("image/png");
+        },
+        // 开始判定
+        submit() {
+            this.isSubmting = true;
+            // 偏差 x = puzzle的起始X - (用户真滑动的距离) + (puzzle的宽度 - 滑块的宽度) * (用户真滑动的距离/canvas总宽度)
+            // 最后+ 的是补上slider和滑块宽度不一致造成的缝隙
+            const x = Math.abs(
+                this.pinX -
+                (this.styleWidth - this.sliderBaseSize) +
+                (this.puzzleBaseSize - this.sliderBaseSize) *
+                ((this.styleWidth - this.sliderBaseSize) /
+                    (this.canvasWidth - this.sliderBaseSize)) -
+                3
+            );
+            if (x < this.range) {
+                // 成功
+                this.infoText = this.successText;
+                this.infoBoxFail = false;
+                this.infoBoxShow = true;
+                this.isCanSlide = false;
+                this.isSuccess = true;
+                // 成功后准备关闭
+                clearTimeout(this.timer1);
+                this.timer1 = setTimeout(() => {
+                    // 成功的回调
+                    this.isSubmting = false;
+                    this.$emit("success", x);
+                }, 800);
+            } else {
+                // 失败
+                this.infoText = this.failText;
+                this.infoBoxFail = true;
+                this.infoBoxShow = true;
+                this.isCanSlide = false;
+                // 失败的回调
+                this.$emit("fail", x);
+                // 800ms后重置
+                clearTimeout(this.timer1);
+                this.timer1 = setTimeout(() => {
+                    this.isSubmting = false;
+                    this.reset();
+                }, 800);
+            }
+        },
+        // 重置 - 重新设置初始状态
+        resetState() {
+            this.infoBoxFail = false;
+            this.infoBoxShow = false;
+            this.isCanSlide = false;
+            this.isSuccess = false;
+            this.startWidth = this.sliderBaseSize; // 鼠标点下去时父级的width
+            this.startX = 0; // 鼠标按下时的X
+            this.newX = 0; // 鼠标当前的偏移X
+        },
+
+        // 重置
+        reset() {
+            if(this.isSubmting){
+                return;
+            }
+            this.resetState();
+            this.init();
+        }
+    }
+
+});

File diff suppressed because it is too large
+ 34 - 0
public/assets/v1/common/lib/echart/echarts.min.js


BIN
public/assets/v1/common/lib/element-ui/fonts/element-icons.ttf


BIN
public/assets/v1/common/lib/element-ui/fonts/element-icons.woff


File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/lib/element-ui/index.css


File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/lib/element-ui/index.js


+ 28 - 0
public/assets/v1/common/lib/imageEditor/.project

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>imageEditor</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>com.aptana.ide.core.unifiedBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>com.aptana.projects.webnature</nature>
+	</natures>
+	<filteredResources>
+		<filter>
+			<id>1513565027028</id>
+			<name></name>
+			<type>26</type>
+			<matcher>
+				<id>org.eclipse.ui.ide.multiFilter</id>
+				<arguments>1.0-name-matches-false-false-node_modules</arguments>
+			</matcher>
+		</filter>
+	</filteredResources>
+</projectDescription>

+ 128 - 0
public/assets/v1/common/lib/imageEditor/css/tui-image-editor.css

@@ -0,0 +1,128 @@
+.border {
+    border: 1px solid black;
+}
+.body-container {
+    width: 1000px;
+}
+.tui-image-editor-controls {
+    min-height: 250px;
+}
+.menu {
+    padding: 0;
+    margin-bottom: 5px;
+    text-align: center;
+    color:#544B61;
+    font-weight: 400;
+    list-style-type: none;
+    user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    -webkit-user-select: none;
+}
+.logo {
+    margin: 0 auto;
+    width: 300px;
+    vertical-align: middle;
+}
+.header .name {
+    padding: 10px;
+    line-height:50px;
+    font-size: 30px;
+    font-weight: 100;
+    vertical-align: middle;
+}
+.header .menu {
+    display: inline-block;
+}
+.menu-item {
+    padding: 10px;
+    display: inline-block;
+    cursor: pointer;
+    vertical-align: middle;
+}
+.menu-item a {
+    text-decoration: none;
+}
+.menu-item.no-pointer {
+    cursor: default;
+}
+.menu-item.active,
+.menu-item:hover {
+    background-color:#f3f3f3;
+}
+.menu-item.disabled {
+    cursor: default;
+    color: #BFBEBE;
+}
+.align-left-top {
+    text-align: left;
+    vertical-align: top;
+}
+.range-narrow {
+    width: 80px;
+}
+.sub-menu-container {
+    font-size: 14px;
+    margin-bottom: 1em;
+    display: none;
+}
+.tui-image-editor {
+    height: 500px;
+}
+.tui-image-editor-canvas-container {
+    margin: 0 auto;
+    top: 50%;
+    transform: translateY(-50%);
+    -ms-transform: translateY(-50%);
+    -moz-transform: translateY(-50%);
+    -webkit-transform: translateY(-50%);
+    border: 1px dashed black;
+    overflow: hidden;
+}
+.tui-colorpicker-container {
+    margin: 5px auto 0;
+}
+.tui-colorpicker-palette-toggle-slider {
+    display: none;
+}
+.input-wrapper{
+    position: relative;
+}
+.input-wrapper input{
+    cursor: pointer;
+    position: absolute;
+    font-size: 999px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+}
+.btn-text-style{
+    padding: 5px;
+    margin: 3px 1px;
+    border: 1px dashed #bfbebe;
+    outline: 0;
+    background-color: #eee;
+    cursor: pointer;
+}
+.icon-text{
+    font-size: 20px;
+}
+.select-line-type{
+    outline: 0;
+    vertical-align: middle;
+}
+#tui-color-picker{
+    display: inline-block;
+    vertical-align: middle;
+}
+#tui-text-palette{
+    display: none;
+    position: absolute;
+    padding: 10px;
+    border: 1px solid #bfbebe;
+    background-color: #fff;
+    z-index: 9999;
+}

+ 231 - 0
public/assets/v1/common/lib/imageEditor/index.html

@@ -0,0 +1,231 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="UTF-8">
+        <title>Image editor basic</title>
+        <link type="text/css" href="css/colorpicker.min.css" rel="stylesheet">
+        <link type="text/css" href="css/tui-image-editor.css" rel="stylesheet">
+    </head>
+    <body>
+        <div class="body-container">
+            <div class="tui-image-editor-controls">
+                <div class="header">
+                    <ul class="menu">
+                        <li class="menu-item border input-wrapper">
+                            Load
+                            <input type="file" accept="image/*" id="input-image-file">
+                        </li>
+                        <li class="menu-item border" id="btn-download">Download</li>
+                    </ul>
+                </div>
+                <ul class="menu">
+                    <li class="menu-item disabled" id="btn-undo">Undo(撤销)</li>
+                    <li class="menu-item disabled" id="btn-redo">Redo(重做)</li>
+                    <li class="menu-item" id="btn-clear-objects">ClearObjects(清除编辑)</li>
+                    <li class="menu-item" id="btn-remove-active-object">RemoveActiveObject(移除操作区)</li>
+                    <li class="menu-item" id="btn-crop">Crop(剪切)</li>
+                    <li class="menu-item" id="btn-flip">Flip(翻转)</li>
+                    <li class="menu-item" id="btn-rotation">Rotation(旋转)</li>
+                    <li class="menu-item" id="btn-draw-line">DrawLine(画笔)</li>
+                    <li class="menu-item" id="btn-draw-shape">Shape(添加形状)</li>
+                    <li class="menu-item" id="btn-add-icon">Icon(添加图标)</li>
+                    <li class="menu-item" id="btn-text">Text(添加文字)</li>
+                    <li class="menu-item" id="btn-mask-filter">Mask(模糊)</li>
+                    <li class="menu-item" id="btn-image-filter">Filter(过滤器)</li>
+                </ul>
+                <div class="sub-menu-container" id="crop-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item" id="btn-apply-crop">Apply(应用)</li>
+                        <li class="menu-item" id="btn-cancel-crop">Cancel(取消)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="flip-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item" id="btn-flip-x">FlipX(左右翻转)</li>
+                        <li class="menu-item" id="btn-flip-y">FlipY(上下翻转)</li>
+                        <li class="menu-item" id="btn-reset-flip">Reset(重置)</li>
+                        <li class="menu-item close">Close(关闭)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="rotation-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item" id="btn-rotate-clockwise">Clockwise(30)(顺时针30度)</li>
+                        <li class="menu-item" id="btn-rotate-counter-clockwise">Counter-Clockwise(-30)(逆时针30度)</li>
+                        <li class="menu-item no-pointer"><label>Range input(范围)<input id="input-rotation-range" type="range" min="-360" value="0" max="360"></label></li>
+                        <li class="menu-item close">Close(关闭)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container menu" id="draw-line-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item">
+                            <label><input type="radio" name="select-line-type" value="freeDrawing" checked="checked"> Free drawing(自由画笔)</label>
+                            <label><input type="radio" name="select-line-type" value="lineDrawing"> Straight line(画线)</label>
+                        </li>
+                        <li class="menu-item">
+                            <div id="tui-brush-color-picker">Brush color</div>
+                        </li>
+                        <li class="menu-item"><label class="menu-item no-pointer">Brush width(画笔宽)<input id="input-brush-width-range" type="range" min="5" max="30" value="12"></label></li>
+                        <li class="menu-item close">Close</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="draw-shape-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item">
+                            <label><input type="radio" name="select-shape-type" value="rect" checked="checked"> rect(方形)</label>
+                            <label><input type="radio" name="select-shape-type" value="circle"> circle(圆形)</label>
+                            <label><input type="radio" name="select-shape-type" value="triangle"> triangle(三角形)</label>
+                        </li>
+                        <li class="menu-item">
+                            <select name="select-color-type">
+                                <option value="fill">Fill</option>
+                                <option value="stroke">Stroke</option>
+                            </select>
+                            <label><input type="checkbox" id="input-check-transparent">transparent(透明)</label>
+                            <div id="tui-shape-color-picker"></div>
+                        </li>
+                        <li class="menu-item"><label class="menu-item no-pointer">Stroke width(边宽)<input id="input-stroke-width-range" type="range" min="0" max="300" value="12"></label></li>
+                        <li class="menu-item close">Close</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="icon-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item">
+                            <div id="tui-icon-color-picker">Icon color(图标颜色)</div>
+                        </li>
+                        <li class="menu-item border" id="btn-register-icon">Register custom icon(注册新增图标)</li>
+                        <li class="menu-item icon-text" data-icon-type="arrow">➡</li>
+                        <li class="menu-item icon-text" data-icon-type="cancel">✖</li>
+                        <li class="menu-item close">Close(关闭)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="text-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item">
+                            <div>
+                                <button class="btn-text-style" data-style-type="b">Bold(粗体)</button>
+                                <button class="btn-text-style" data-style-type="i">Italic(斜体)</button>
+                                <button class="btn-text-style" data-style-type="u">Underline(下划线)</button>
+                            </div>
+                            <div>
+                                <button class="btn-text-style" data-style-type="l">Left(靠左)</button>
+                                <button class="btn-text-style" data-style-type="c">Center(居中)</button>
+                                <button class="btn-text-style" data-style-type="r">Right(靠右)</button>
+                            </div>
+                        </li>
+                        <li class="menu-item"><label class="no-pointer"><input id="input-font-size-range" type="range" min="10" max="100" value="10"></label></li>
+                        <li class="menu-item">
+                            <div id="tui-text-color-picker">Text color(文字颜色)</div>
+                        </li>
+                        <li class="menu-item close">Close(关闭)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="filter-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item border input-wrapper">
+                            Load Mask Image(上传模糊图片)
+                            <input type="file" accept="image/*" id="input-mask-image-file">
+                        </li>
+                        <li class="menu-item" id="btn-apply-mask">Apply mask filter(应用模糊过滤)</li>
+                        <li class="menu-item close">Close(关闭)</li>
+                    </ul>
+                </div>
+                <div class="sub-menu-container" id="image-filter-sub-menu">
+                    <ul class="menu">
+                        <li class="menu-item align-left-top">
+                            <table>
+                                <tbody>
+                                    <tr>
+                                        <td><label><input type="checkbox" id="input-check-grayscale">Grayscale</label></td>
+                                        <td><label><input type="checkbox" id="input-check-invert">Invert</label></td>
+                                        <td><label><input type="checkbox" id="input-check-sepia">Sepia</label></td>
+                                    </tr>
+                                    <tr>
+                                        <td><label><input type="checkbox" id="input-check-sepia2">Sepia2</label></td>
+                                        <td><label><input type="checkbox" id="input-check-blur">Blur</label></td>
+                                        <td><label><input type="checkbox" id="input-check-sharpen">Sharpen</label></td>
+                                    </tr>
+                                    <tr>
+                                        <td><label><input type="checkbox" id="input-check-emboss">Emboss</label></td>
+                                    </tr>
+                                </tbody>
+                            </table>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-remove-white">RemoveWhite</label><br>
+                                <label>Threshold<input class="range-narrow" id="input-range-remove-white-threshold" type="range" min="0" value="60" max="255"></label><br>
+                                <label>Distance<input class="range-narrow" id="input-range-remove-white-distance" type="range" min="0" value="10" max="255"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-brightness">Brightness</label><br>
+                                <label>Value<input class="range-narrow" id="input-range-brightness-value" type="range" min="-255" value="100" max="255"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-noise">Noise</label><br>
+                                <label>Value<input class="range-narrow" id="input-range-noise-value" type="range" min="0" value="100" max="1000"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-gradient-transparancy">GradientTransparency</label><br>
+                                <label>Value<input class="range-narrow" id="input-range-gradient-transparency-value" type="range" min="0" value="100" max="255"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-pixelate">Pixelate</label><br>
+                                <label>Value<input class="range-narrow" id="input-range-pixelate-value" type="range" min="2" value="4" max="20"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-tint">Tint</label><br>
+                                <div id="tui-tint-color-picker"></div>
+                                <label>Opacity<input class="range-narrow" id="input-range-tint-opacity-value" type="range" min="0" value="1" max="1" step="0.1"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-multiply">Multiply</label>
+                                <div id="tui-multiply-color-picker"></div>
+                            </p>
+                        </li>
+                        <li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-blend">Blend</label>
+                                <div id="tui-blend-color-picker"></div>
+                                <select name="select-blend-type">
+                                    <option value="add" selected>Add</option>
+                                    <option value="diff">Diff</option>
+                                    <option value="diff">Subtract</option>
+                                    <option value="multiply">Multiply</option>
+                                    <option value="screen">Screen</option>
+                                    <option value="lighten">Lighten</option>
+                                    <option value="darken">Darken</option>
+                                </select>
+                            </p>
+                        </li><li class="menu-item align-left-top">
+                            <p>
+                                <label><input type="checkbox" id="input-check-color-filter">ColorFilter</label><br>
+                                <label>Threshold<input class="range-narrow" id="input-range-color-filter-value" type="range" min="0" value="45" max="255"></label>
+                            </p>
+                        </li>
+                        <li class="menu-item close">Close</li>
+                    </ul>
+                </div>
+            </div>
+            <div class="tui-image-editor"></div>
+        </div>
+        <script type="text/javascript" src="libs/fabric.js"></script>
+        <script type="text/javascript" src="libs/tui-code-snippet.js"></script>
+        <script type="text/javascript" src="libs/jquery.min.js"></script>
+        <script type="text/javascript" src="libs/FileSaver.min.js"></script>
+        <script type="text/javascript" src="libs/colorpicker.min.js"></script>
+        <script type="text/javascript" src="libs/tui-image-editor.min.js"></script>
+        <script src="js/basic.js"></script>
+    </body>
+</html>

+ 934 - 0
public/assets/v1/common/lib/imageEditor/js/basic.js

@@ -0,0 +1,934 @@
+/**
+ * basic.js
+ * @author NHN Ent. FE Development Team <dl_javascript@nhnent.com>
+ * @fileoverview
+ */
+'use strict';
+
+var supportingFileAPI = !!(window.File && window.FileList && window.FileReader);
+var rImageType = /data:(image\/.+);base64,/;
+var shapeOptions = {};
+var shapeType;
+var activeObjectId;
+
+// Buttons
+var $btns = $('.menu-item');
+var $btnsActivatable = $btns.filter('.activatable');
+var $inputImage = $('#input-image-file');
+var $btnDownload = $('#btn-download');
+
+var $btnUndo = $('#btn-undo');
+var $btnRedo = $('#btn-redo');
+var $btnClearObjects = $('#btn-clear-objects');
+var $btnRemoveActiveObject = $('#btn-remove-active-object');
+var $btnCrop = $('#btn-crop');
+var $btnFlip = $('#btn-flip');
+var $btnRotation = $('#btn-rotation');
+var $btnDrawLine = $('#btn-draw-line');
+var $btnDrawShape = $('#btn-draw-shape');
+var $btnApplyCrop = $('#btn-apply-crop');
+var $btnCancelCrop = $('#btn-cancel-crop');
+var $btnFlipX = $('#btn-flip-x');
+var $btnFlipY = $('#btn-flip-y');
+var $btnResetFlip = $('#btn-reset-flip');
+var $btnRotateClockwise = $('#btn-rotate-clockwise');
+var $btnRotateCounterClockWise = $('#btn-rotate-counter-clockwise');
+var $btnText = $('#btn-text');
+var $btnTextStyle = $('.btn-text-style');
+var $btnAddIcon = $('#btn-add-icon');
+var $btnRegisterIcon = $('#btn-register-icon');
+var $btnMaskFilter = $('#btn-mask-filter');
+var $btnImageFilter = $('#btn-image-filter');
+var $btnLoadMaskImage = $('#input-mask-image-file');
+var $btnApplyMask = $('#btn-apply-mask');
+var $btnClose = $('.close');
+
+// Input etc.
+var $inputRotationRange = $('#input-rotation-range');
+var $inputBrushWidthRange = $('#input-brush-width-range');
+var $inputFontSizeRange = $('#input-font-size-range');
+var $inputStrokeWidthRange = $('#input-stroke-width-range');
+var $inputCheckTransparent = $('#input-check-transparent');
+var $inputCheckGrayscale = $('#input-check-grayscale');
+var $inputCheckInvert = $('#input-check-invert');
+var $inputCheckSepia = $('#input-check-sepia');
+var $inputCheckSepia2 = $('#input-check-sepia2');
+var $inputCheckBlur = $('#input-check-blur');
+var $inputCheckSharpen = $('#input-check-sharpen');
+var $inputCheckEmboss = $('#input-check-emboss');
+var $inputCheckRemoveWhite = $('#input-check-remove-white');
+var $inputRangeRemoveWhiteThreshold = $('#input-range-remove-white-threshold');
+var $inputRangeRemoveWhiteDistance = $('#input-range-remove-white-distance');
+var $inputCheckBrightness = $('#input-check-brightness');
+var $inputRangeBrightnessValue = $('#input-range-brightness-value');
+var $inputCheckNoise = $('#input-check-noise');
+var $inputRangeNoiseValue = $('#input-range-noise-value');
+var $inputCheckGradientTransparency = $('#input-check-gradient-transparancy');
+var $inputRangeGradientTransparencyValue = $('#input-range-gradient-transparency-value');
+var $inputCheckPixelate = $('#input-check-pixelate');
+var $inputRangePixelateValue = $('#input-range-pixelate-value');
+var $inputCheckTint = $('#input-check-tint');
+var $inputRangeTintOpacityValue = $('#input-range-tint-opacity-value');
+var $inputCheckMultiply = $('#input-check-multiply');
+var $inputCheckBlend = $('#input-check-blend');
+var $inputCheckColorFilter = $('#input-check-color-filter');
+var $inputRangeColorFilterValue = $('#input-range-color-filter-value');
+
+// Sub menus
+var $displayingSubMenu = $();
+var $cropSubMenu = $('#crop-sub-menu');
+var $flipSubMenu = $('#flip-sub-menu');
+var $rotationSubMenu = $('#rotation-sub-menu');
+var $freeDrawingSubMenu = $('#free-drawing-sub-menu');
+var $drawLineSubMenu = $('#draw-line-sub-menu');
+var $drawShapeSubMenu = $('#draw-shape-sub-menu');
+var $textSubMenu = $('#text-sub-menu');
+var $iconSubMenu = $('#icon-sub-menu');
+var $filterSubMenu = $('#filter-sub-menu');
+var $imageFilterSubMenu = $('#image-filter-sub-menu');
+
+// Select line type
+var $selectLine = $('[name="select-line-type"]');
+
+// Select shape type
+var $selectShapeType = $('[name="select-shape-type"]');
+
+// Select color of shape type
+var $selectColorType = $('[name="select-color-type"]');
+
+//Select blend type
+var $selectBlendType = $('[name="select-blend-type"]');
+
+// Image editor
+var imageEditor = new tui.ImageEditor('.tui-image-editor', {
+    cssMaxWidth: 700,
+    cssMaxHeight: 500,
+    selectionStyle: {
+        cornerSize: 20,
+        rotatingPointOffset: 70
+    }
+});
+
+// Color picker for free drawing
+var brushColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-brush-color-picker')[0],
+    color: '#000000'
+});
+
+// Color picker for text palette
+var textColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-text-color-picker')[0],
+    color: '#000000'
+});
+
+// Color picker for shape
+var shapeColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-shape-color-picker')[0],
+    color: '#000000'
+});
+
+// Color picker for icon
+var iconColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-icon-color-picker')[0],
+    color: '#000000'
+});
+
+var tintColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-tint-color-picker')[0],
+    color: '#000000'
+});
+
+var multiplyColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-multiply-color-picker')[0],
+    color: '#000000'
+});
+
+var blendColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-blend-color-picker')[0],
+    color: '#00FF00'
+});
+
+// Common global functions
+// HEX to RGBA
+function hexToRGBa(hex, alpha) {
+    var r = parseInt(hex.slice(1, 3), 16);
+    var g = parseInt(hex.slice(3, 5), 16);
+    var b = parseInt(hex.slice(5, 7), 16);
+    var a = alpha || 1;
+
+    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
+}
+
+function base64ToBlob(data) {
+    var mimeString = '';
+    var raw, uInt8Array, i, rawLength;
+
+    raw = data.replace(rImageType, function(header, imageType) {
+        mimeString = imageType;
+
+        return '';
+    });
+
+    raw = atob(raw);
+    rawLength = raw.length;
+    uInt8Array = new Uint8Array(rawLength); // eslint-disable-line
+
+    for (i = 0; i < rawLength; i += 1) {
+        uInt8Array[i] = raw.charCodeAt(i);
+    }
+
+    return new Blob([uInt8Array], {type: mimeString});
+}
+
+function resizeEditor() {
+    var $editor = $('.tui-image-editor');
+    var $container = $('.tui-image-editor-canvas-container');
+    var height = parseFloat($container.css('max-height'));
+
+    $editor.height(height);
+}
+
+function getBrushSettings() {
+    var brushWidth = $inputBrushWidthRange.val();
+    var brushColor = brushColorpicker.getColor();
+
+    return {
+        width: brushWidth,
+        color: hexToRGBa(brushColor, 0.5)
+    };
+}
+
+function activateShapeMode() {
+    if (imageEditor.getDrawingMode() !== 'SHAPE') {
+        imageEditor.stopDrawingMode();
+        imageEditor.startDrawingMode('SHAPE');
+    }
+}
+
+function activateIconMode() {
+    imageEditor.stopDrawingMode();
+}
+
+function activateTextMode() {
+    if (imageEditor.getDrawingMode() !== 'TEXT') {
+        imageEditor.stopDrawingMode();
+        imageEditor.startDrawingMode('TEXT');
+    }
+}
+
+function setTextToolbar(obj) {
+    var fontSize = obj.fontSize;
+    var fontColor = obj.fill;
+
+    $inputFontSizeRange.val(fontSize);
+    textColorpicker.setColor(fontColor);
+}
+
+function setIconToolbar(obj) {
+    var iconColor = obj.fill;
+
+    iconColorpicker.setColor(iconColor);
+}
+
+function setShapeToolbar(obj) {
+    var strokeColor, fillColor, isTransparent;
+    var colorType = $selectColorType.val();
+
+    if (colorType === 'stroke') {
+        strokeColor = obj.stroke;
+        isTransparent = (strokeColor === 'transparent');
+
+        if (!isTransparent) {
+            shapeColorpicker.setColor(strokeColor);
+        }
+    } else if (colorType === 'fill') {
+        fillColor = obj.fill;
+        isTransparent = (fillColor === 'transparent');
+
+        if (!isTransparent) {
+            shapeColorpicker.setColor(fillColor);
+        }
+    }
+
+    $inputCheckTransparent.prop('checked', isTransparent);
+    $inputStrokeWidthRange.val(obj.strokeWidth);
+}
+
+function showSubMenu(type) {
+    var $submenu;
+
+    switch (type) {
+        case 'shape':
+            $submenu = $drawShapeSubMenu;
+            break;
+        case 'icon':
+            $submenu = $iconSubMenu;
+            break;
+        case 'text':
+            $submenu = $textSubMenu;
+            break;
+        default:
+            $submenu = 0;
+    }
+
+    $displayingSubMenu.hide();
+    $displayingSubMenu = $submenu.show();
+}
+
+function applyOrRemoveFilter(applying, type, options) {
+    if (applying) {
+        imageEditor.applyFilter(type, options).then(result => {
+            console.log(result);
+        });
+    } else {
+        imageEditor.removeFilter(type);
+    }
+}
+
+// Attach image editor custom events
+imageEditor.on({
+    objectAdded: function(objectProps) {
+        console.info(objectProps);
+    },
+    undoStackChanged: function(length) {
+        if (length) {
+            $btnUndo.removeClass('disabled');
+        } else {
+            $btnUndo.addClass('disabled');
+        }
+        resizeEditor();
+    },
+    redoStackChanged: function(length) {
+        if (length) {
+            $btnRedo.removeClass('disabled');
+        } else {
+            $btnRedo.addClass('disabled');
+        }
+        resizeEditor();
+    },
+    objectScaled: function(obj) {
+        if (obj.type === 'text') {
+            $inputFontSizeRange.val(obj.fontSize);
+        }
+    },
+    addText: function(pos) {
+        imageEditor.addText('Double Click', {
+            position: pos.originPosition
+        }).then(objectProps => {
+            console.log(objectProps);
+        });
+    },
+    objectActivated: function(obj) {
+        activeObjectId = obj.id;
+        if (obj.type === 'rect' || obj.type === 'circle' || obj.type === 'triangle') {
+            showSubMenu('shape');
+            setShapeToolbar(obj);
+            activateShapeMode();
+        } else if (obj.type === 'icon') {
+            showSubMenu('icon');
+            setIconToolbar(obj);
+            activateIconMode();
+        } else if (obj.type === 'text') {
+            showSubMenu('text');
+            setTextToolbar(obj);
+            activateTextMode();
+        }
+    },
+    mousedown: function(event, originPointer) {
+        if ($imageFilterSubMenu.is(':visible') && imageEditor.hasFilter('colorFilter')) {
+            imageEditor.applyFilter('colorFilter', {
+                x: parseInt(originPointer.x, 10),
+                y: parseInt(originPointer.y, 10)
+            });
+        }
+    }
+});
+
+// Attach button click event listeners
+$btns.on('click', function() {
+    $btnsActivatable.removeClass('active');
+});
+
+$btnsActivatable.on('click', function() {
+    $(this).addClass('active');
+});
+
+$btnUndo.on('click', function() {
+    $displayingSubMenu.hide();
+
+    if (!$(this).hasClass('disabled')) {
+        imageEditor.undo();
+    }
+});
+
+$btnRedo.on('click', function() {
+    $displayingSubMenu.hide();
+
+    if (!$(this).hasClass('disabled')) {
+        imageEditor.redo();
+    }
+});
+
+$btnClearObjects.on('click', function() {
+    $displayingSubMenu.hide();
+    imageEditor.clearObjects();
+});
+
+$btnRemoveActiveObject.on('click', function() {
+    $displayingSubMenu.hide();
+    imageEditor.removeObject(activeObjectId);
+});
+
+$btnCrop.on('click', function() {
+    imageEditor.startDrawingMode('CROPPER');
+    $displayingSubMenu.hide();
+    $displayingSubMenu = $cropSubMenu.show();
+});
+
+$btnFlip.on('click', function() {
+    imageEditor.stopDrawingMode();
+    $displayingSubMenu.hide();
+    $displayingSubMenu = $flipSubMenu.show();
+});
+
+$btnRotation.on('click', function() {
+    imageEditor.stopDrawingMode();
+    $displayingSubMenu.hide();
+    $displayingSubMenu = $rotationSubMenu.show();
+});
+
+$btnClose.on('click', function() {
+    imageEditor.stopDrawingMode();
+    $displayingSubMenu.hide();
+});
+
+$btnApplyCrop.on('click', function() {
+    imageEditor.crop(imageEditor.getCropzoneRect()).then(() => {
+        imageEditor.stopDrawingMode();
+        resizeEditor();
+    });
+});
+
+$btnCancelCrop.on('click', function() {
+    imageEditor.stopDrawingMode();
+});
+
+$btnFlipX.on('click', function() {
+    imageEditor.flipX().then(status => {
+        console.log('flipX: ', status.flipX);
+        console.log('flipY: ', status.flipY);
+        console.log('angle: ', status.angle);
+    });
+});
+
+$btnFlipY.on('click', function() {
+    imageEditor.flipY().then(status => {
+        console.log('flipX: ', status.flipX);
+        console.log('flipY: ', status.flipY);
+        console.log('angle: ', status.angle);
+    });
+});
+
+$btnResetFlip.on('click', function() {
+    imageEditor.resetFlip().then(status => {
+        console.log('flipX: ', status.flipX);
+        console.log('flipY: ', status.flipY);
+        console.log('angle: ', status.angle);
+    });
+});
+
+$btnRotateClockwise.on('click', function() {
+    imageEditor.rotate(30);
+});
+
+$btnRotateCounterClockWise.on('click', function() {
+    imageEditor.rotate(-30);
+});
+
+$inputRotationRange.on('mousedown', function() {
+    var changeAngle = function() {
+        imageEditor.setAngle(parseInt($inputRotationRange.val(), 10)).catch(() => {});
+    };
+    $(document).on('mousemove', changeAngle);
+    $(document).on('mouseup', function stopChangingAngle() {
+        $(document).off('mousemove', changeAngle);
+        $(document).off('mouseup', stopChangingAngle);
+    });
+});
+
+$inputRotationRange.on('change', function() {
+    imageEditor.setAngle(parseInt($inputRotationRange.val(), 10)).catch(() => {});
+});
+
+$inputBrushWidthRange.on('change', function() {
+    imageEditor.setBrush({width: parseInt(this.value, 10)});
+});
+
+$inputImage.on('change', function(event) {
+    var file;
+
+    if (!supportingFileAPI) {
+        alert('This browser does not support file-api');
+    }
+
+    file = event.target.files[0];
+    imageEditor.loadImageFromFile(file).then(result => {
+        console.log(result);
+        imageEditor.clearUndoStack();
+    });
+});
+
+$btnDownload.on('click', function() {
+    var imageName = imageEditor.getImageName();
+    var dataURL = imageEditor.toDataURL();
+    var blob, type, w;
+
+    if (supportingFileAPI) {
+        blob = base64ToBlob(dataURL);
+        type = blob.type.split('/')[1];
+        if (imageName.split('.').pop() !== type) {
+            imageName += '.' + type;
+        }
+
+        // Library: FileSaver - saveAs
+        saveAs(blob, imageName); // eslint-disable-line
+    } else {
+        alert('This browser needs a file-server');
+        w = window.open();
+        w.document.body.innerHTML = '<img src=' + dataURL + '>';
+    }
+});
+
+// control draw line mode
+$btnDrawLine.on('click', function() {
+    imageEditor.stopDrawingMode();
+    $displayingSubMenu.hide();
+    $displayingSubMenu = $drawLineSubMenu.show();
+    $selectLine.eq(0).change();
+});
+
+$selectLine.on('change', function() {
+    var mode = $(this).val();
+    var settings = getBrushSettings();
+
+    imageEditor.stopDrawingMode();
+    if (mode === 'freeDrawing') {
+        imageEditor.startDrawingMode('FREE_DRAWING', settings);
+    } else {
+        imageEditor.startDrawingMode('LINE_DRAWING', settings);
+    }
+});
+
+brushColorpicker.on('selectColor', function(event) {
+    imageEditor.setBrush({
+        color: hexToRGBa(event.color, 0.5)
+    });
+});
+
+// control draw shape mode
+$btnDrawShape.on('click', function() {
+    showSubMenu('shape');
+
+    // step 1. get options to draw shape from toolbar
+    shapeType = $('[name="select-shape-type"]:checked').val();
+
+    shapeOptions.stroke = '#000000';
+    shapeOptions.fill = '#ffffff';
+
+    shapeOptions.strokeWidth = Number($inputStrokeWidthRange.val());
+
+    // step 2. set options to draw shape
+    imageEditor.setDrawingShape(shapeType, shapeOptions);
+
+    // step 3. start drawing shape mode
+    activateShapeMode();
+});
+
+$selectShapeType.on('change', function() {
+    shapeType = $(this).val();
+
+    imageEditor.setDrawingShape(shapeType);
+});
+
+$inputCheckTransparent.on('change', function() {
+    var colorType = $selectColorType.val();
+    var isTransparent = $(this).prop('checked');
+    var color;
+
+    if (!isTransparent) {
+        color = shapeColorpicker.getColor();
+    } else {
+        color = 'transparent';
+    }
+
+    if (colorType === 'stroke') {
+        imageEditor.changeShape(activeObjectId, {
+            stroke: color
+        });
+    } else if (colorType === 'fill') {
+        imageEditor.changeShape(activeObjectId, {
+            fill: color
+        });
+    }
+
+    imageEditor.setDrawingShape(shapeType, shapeOptions);
+});
+
+shapeColorpicker.on('selectColor', function(event) {
+    var colorType = $selectColorType.val();
+    var isTransparent = $inputCheckTransparent.prop('checked');
+    var color = event.color;
+
+    if (isTransparent) {
+        return;
+    }
+
+    if (colorType === 'stroke') {
+        imageEditor.changeShape(activeObjectId, {
+            stroke: color
+        });
+    } else if (colorType === 'fill') {
+        imageEditor.changeShape(activeObjectId, {
+            fill: color
+        });
+    }
+
+    imageEditor.setDrawingShape(shapeType, shapeOptions);
+});
+
+$inputStrokeWidthRange.on('change', function() {
+    var strokeWidth = Number($(this).val());
+
+    imageEditor.changeShape(activeObjectId, {
+        strokeWidth: strokeWidth
+    });
+
+    imageEditor.setDrawingShape(shapeType, shapeOptions);
+});
+
+// control text mode
+$btnText.on('click', function() {
+    showSubMenu('text');
+    activateTextMode();
+});
+
+$inputFontSizeRange.on('change', function() {
+    imageEditor.changeTextStyle(activeObjectId, {
+        fontSize: parseInt(this.value, 10)
+    });
+});
+
+$btnTextStyle.on('click', function(e) { // eslint-disable-line
+    var styleType = $(this).attr('data-style-type');
+    var styleObj;
+
+    e.stopPropagation();
+
+    switch (styleType) {
+        case 'b':
+            styleObj = {fontWeight: 'bold'};
+            break;
+        case 'i':
+            styleObj = {fontStyle: 'italic'};
+            break;
+        case 'u':
+            styleObj = {textDecoration: 'underline'};
+            break;
+        case 'l':
+            styleObj = {textAlign: 'left'};
+            break;
+        case 'c':
+            styleObj = {textAlign: 'center'};
+            break;
+        case 'r':
+            styleObj = {textAlign: 'right'};
+            break;
+        default:
+            styleObj = {};
+    }
+
+    imageEditor.changeTextStyle(activeObjectId, styleObj);
+});
+
+textColorpicker.on('selectColor', function(event) {
+    imageEditor.changeTextStyle(activeObjectId, {
+        'fill': event.color
+    });
+});
+
+// control icon
+$btnAddIcon.on('click', function() {
+    showSubMenu('icon');
+    activateIconMode();
+});
+
+function onClickIconSubMenu(event) {
+    var element = event.target || event.srcElement;
+    var iconType = $(element).attr('data-icon-type');
+
+    imageEditor.once('mousedown', function(e, originPointer) {
+        imageEditor.addIcon(iconType, {
+            left: originPointer.x,
+            top: originPointer.y
+        }).then(objectProps => {
+            console.log(objectProps);
+        });
+    });
+}
+
+$btnRegisterIcon.on('click', function() {
+    $iconSubMenu.find('.menu-item').eq(3).after(
+        '<li id="customArrow" class="menu-item icon-text" data-icon-type="customArrow">↑</li>'
+    );
+
+    imageEditor.registerIcons({
+        customArrow: 'M 60 0 L 120 60 H 90 L 75 45 V 180 H 45 V 45 L 30 60 H 0 Z'
+    });
+
+    $btnRegisterIcon.off('click');
+
+    $iconSubMenu.on('click', '#customArrow', onClickIconSubMenu);
+});
+
+$iconSubMenu.on('click', '.icon-text', onClickIconSubMenu);
+
+iconColorpicker.on('selectColor', function(event) {
+    imageEditor.changeIconColor(activeObjectId, event.color);
+});
+
+// control mask filter
+$btnMaskFilter.on('click', function() {
+    imageEditor.stopDrawingMode();
+    $displayingSubMenu.hide();
+
+    $displayingSubMenu = $filterSubMenu.show();
+});
+
+$btnImageFilter.on('click', function() {
+    var filters = {
+        'grayscale': $inputCheckGrayscale,
+        'invert': $inputCheckInvert,
+        'sepia': $inputCheckSepia,
+        'sepia2': $inputCheckSepia2,
+        'blur': $inputCheckBlur,
+        'shapren': $inputCheckSharpen,
+        'emboss': $inputCheckEmboss,
+        'removeWhite': $inputCheckRemoveWhite,
+        'brightness': $inputCheckBrightness,
+        'noise': $inputCheckNoise,
+        'gradientTransparency': $inputCheckGradientTransparency,
+        'pixelate': $inputCheckPixelate,
+        'tint': $inputCheckTint,
+        'multiply': $inputCheckMultiply,
+        'blend': $inputCheckBlend,
+        'colorFilter': $inputCheckColorFilter
+    };
+
+    tui.util.forEach(filters, function($value, key) {
+        $value.prop('checked', imageEditor.hasFilter(key));
+    });
+    $displayingSubMenu.hide();
+
+    $displayingSubMenu = $imageFilterSubMenu.show();
+});
+
+$btnLoadMaskImage.on('change', function() {
+    var file;
+    var imgUrl;
+
+    if (!supportingFileAPI) {
+        alert('This browser does not support file-api');
+    }
+
+    file = event.target.files[0];
+
+    if (file) {
+        imgUrl = URL.createObjectURL(file);
+
+        imageEditor.loadImageFromURL(imageEditor.toDataURL(), 'FilterImage').then(() => {
+            imageEditor.addImageObject(imgUrl).then(objectProps => {
+                URL.revokeObjectURL(file);
+                console.log(objectProps);
+            });
+        });
+    }
+});
+
+$btnApplyMask.on('click', function() {
+    imageEditor.applyFilter('mask', {
+        maskObjId: activeObjectId
+    }).then(result => {
+        console.log(result);
+    });
+});
+
+$inputCheckGrayscale.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Grayscale', null);
+});
+
+$inputCheckInvert.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Invert', null);
+});
+
+$inputCheckSepia.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Sepia', null);
+});
+
+$inputCheckSepia2.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Sepia2', null);
+});
+
+$inputCheckBlur.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Blur', null);
+});
+
+$inputCheckSharpen.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Sharpen', null);
+});
+
+$inputCheckEmboss.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'Emboss', null);
+});
+
+$inputCheckRemoveWhite.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'removeWhite', {
+        threshold: parseInt($inputRangeRemoveWhiteThreshold.val(), 10),
+        distance: parseInt($inputRangeRemoveWhiteDistance.val(), 10)
+    });
+});
+
+$inputRangeRemoveWhiteThreshold.on('change', function() {
+    applyOrRemoveFilter($inputCheckRemoveWhite.is(':checked'), 'removeWhite', {
+        threshold: parseInt(this.value, 10)
+    });
+});
+
+$inputRangeRemoveWhiteDistance.on('change', function() {
+    applyOrRemoveFilter($inputCheckRemoveWhite.is(':checked'), 'removeWhite', {
+        distance: parseInt(this.value, 10)
+    });
+});
+
+$inputCheckBrightness.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'brightness', {
+        brightness: parseInt($inputRangeBrightnessValue.val(), 10)
+    });
+});
+
+$inputRangeBrightnessValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckBrightness.is(':checked'), 'brightness', {
+        brightness: parseInt(this.value, 10)
+    });
+});
+
+$inputCheckNoise.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'noise', {
+        noise: parseInt($inputRangeNoiseValue.val(), 10)
+    });
+});
+
+$inputRangeNoiseValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckNoise.is(':checked'), 'noise', {
+        noise: parseInt(this.value, 10)
+    });
+});
+
+$inputCheckGradientTransparency.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'gradientTransparency', {
+        threshold: parseInt($inputRangeGradientTransparencyValue.val(), 10)
+    });
+});
+
+$inputRangeGradientTransparencyValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckGradientTransparency.is(':checked'), 'gradientTransparency', {
+        threshold: parseInt(this.value, 10)
+    });
+});
+
+$inputCheckPixelate.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'pixelate', {
+        blocksize: parseInt($inputRangePixelateValue.val(), 10)
+    });
+});
+
+$inputRangePixelateValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckPixelate.is(':checked'), 'pixelate', {
+        blocksize: parseInt(this.value, 10)
+    });
+});
+
+$inputCheckTint.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'tint', {
+        color: tintColorpicker.getColor(),
+        opacity: parseFloat($inputRangeTintOpacityValue.val())
+    });
+});
+
+tintColorpicker.on('selectColor', function(e) {
+    applyOrRemoveFilter($inputCheckTint.is(':checked'), 'tint', {
+        color: e.color
+    });
+});
+
+$inputRangeTintOpacityValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckTint.is(':checked'), 'tint', {
+        opacity: parseFloat($inputRangeTintOpacityValue.val())
+    });
+});
+
+$inputCheckMultiply.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'multiply', {
+        color: multiplyColorpicker.getColor()
+    });
+});
+
+multiplyColorpicker.on('selectColor', function(e) {
+    applyOrRemoveFilter($inputCheckMultiply.is(':checked'), 'multiply', {
+        color: e.color
+    });
+});
+
+$inputCheckBlend.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'blend', {
+        color: blendColorpicker.getColor(),
+        mode: $selectBlendType.val()
+    });
+});
+
+blendColorpicker.on('selectColor', function(e) {
+    applyOrRemoveFilter($inputCheckBlend.is(':checked'), 'blend', {
+        color: e.color
+    });
+});
+
+$selectBlendType.on('change', function() {
+    applyOrRemoveFilter($inputCheckBlend.is(':checked'), 'blend', {
+        mode: this.value
+    });
+});
+
+$inputCheckColorFilter.on('change', function() {
+    applyOrRemoveFilter(this.checked, 'colorFilter', {
+        color: '#FFFFFF',
+        threshold: $inputRangeColorFilterValue.val()
+    });
+});
+
+$inputRangeColorFilterValue.on('change', function() {
+    applyOrRemoveFilter($inputCheckColorFilter.is(':checked'), 'colorFilter', {
+        threshold: this.value
+    });
+});
+
+// Etc..
+
+// Load sample image
+imageEditor.loadImageFromURL('/statics/v1/library/imageEditor/img/sampleImage.jpg', 'SampleImage').then(sizeValue => {
+    console.log(sizeValue);
+    imageEditor.clearUndoStack();
+});
+
+// IE9 Unselectable
+$('.menu').on('selectstart', function() {
+    return false;
+});

+ 570 - 0
public/assets/v1/common/lib/imageEditor/js/mobile.js

@@ -0,0 +1,570 @@
+/**
+ * mobile.js
+ * @author NHN Ent. FE Development Team <dl_javascript@nhnent.com>
+ * @fileoverview
+ */
+/* eslint-disable vars-on-top */
+'use strict';
+
+var MAX_RESOLUTION = 3264 * 2448; // 8MP (Mega Pixel)
+
+var supportingFileAPI = !!(window.File && window.FileList && window.FileReader);
+var rImageType = /data:(image\/.+);base64,/;
+var shapeOpt = {
+    fill: '#fff',
+    stroke: '#000',
+    strokeWidth: 10
+};
+var activeObjectId;
+
+// Selector of image editor controls
+var submenuClass = '.submenu';
+var hiddenmenuClass = '.hiddenmenu';
+
+var $controls = $('.tui-image-editor-controls');
+var $menuButtons = $controls.find('.menu-button');
+var $submenuButtons = $controls.find('.submenu-button');
+var $btnShowMenu = $controls.find('.btn-prev');
+var $msg = $controls.find('.msg');
+
+var $subMenus = $controls.find(submenuClass);
+var $hiddenMenus = $controls.find(hiddenmenuClass);
+
+// Image editor controls - top menu buttons
+var $inputImage = $('#input-image-file');
+var $btnDownload = $('#btn-download');
+var $btnUndo = $('#btn-undo');
+var $btnRedo = $('#btn-redo');
+var $btnRemoveActiveObject = $('#btn-remove-active-object');
+
+// Image editor controls - bottom menu buttons
+var $btnCrop = $('#btn-crop');
+var $btnAddText = $('#btn-add-text');
+
+// Image editor controls - bottom submenu buttons
+var $btnApplyCrop = $('#btn-apply-crop');
+var $btnFlipX = $('#btn-flip-x');
+var $btnFlipY = $('#btn-flip-y');
+var $btnRotateClockwise = $('#btn-rotate-clockwise');
+var $btnRotateCounterClockWise = $('#btn-rotate-counter-clockwise');
+var $btnAddArrowIcon = $('#btn-add-arrow-icon');
+var $btnAddCancelIcon = $('#btn-add-cancel-icon');
+var $btnAddCustomIcon = $('#btn-add-custom-icon');
+var $btnFreeDrawing = $('#btn-free-drawing');
+var $btnLineDrawing = $('#btn-line-drawing');
+var $btnAddRect = $('#btn-add-rect');
+var $btnAddSquare = $('#btn-add-square');
+var $btnAddEllipse = $('#btn-add-ellipse');
+var $btnAddCircle = $('#btn-add-circle');
+var $btnAddTriangle = $('#btn-add-triangle');
+var $btnChangeTextStyle = $('.btn-change-text-style');
+
+// Image editor controls - etc.
+var $inputTextSizeRange = $('#input-text-size-range');
+var $inputBrushWidthRange = $('#input-brush-range');
+var $inputStrokeWidthRange = $('#input-stroke-range');
+var $inputCheckTransparent = $('#input-check-transparent');
+
+// Colorpicker
+var iconColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-icon-color-picker')[0],
+    color: '#000000'
+});
+
+var textColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-text-color-picker')[0],
+    color: '#000000'
+});
+
+var brushColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-brush-color-picker')[0],
+    color: '#000000'
+});
+
+var shapeColorpicker = tui.component.colorpicker.create({
+    container: $('#tui-shape-color-picker')[0],
+    color: '#000000'
+});
+
+// Create image editor
+var imageEditor = new tui.ImageEditor('.tui-image-editor', {
+    cssMaxWidth: document.documentElement.clientWidth,
+    cssMaxHeight: document.documentElement.clientHeight,
+    selectionStyle: {
+        cornerSize: 50,
+        rotatingPointOffset: 100
+    }
+});
+
+var $displayingSubMenu, $displayingHiddenMenu;
+
+function hexToRGBa(hex, alpha) {
+    var r = parseInt(hex.slice(1, 3), 16);
+    var g = parseInt(hex.slice(3, 5), 16);
+    var b = parseInt(hex.slice(5, 7), 16);
+    var a = alpha || 1;
+
+    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
+}
+
+function base64ToBlob(data) {
+    var mimeString = '';
+    var raw, uInt8Array, i, rawLength;
+
+    raw = data.replace(rImageType, function(header, imageType) {
+        mimeString = imageType;
+
+        return '';
+    });
+
+    raw = atob(raw);
+    rawLength = raw.length;
+    uInt8Array = new Uint8Array(rawLength); // eslint-disable-line
+
+    for (i = 0; i < rawLength; i += 1) {
+        uInt8Array[i] = raw.charCodeAt(i);
+    }
+
+    return new Blob([uInt8Array], {type: mimeString});
+}
+
+function getBrushSettings() {
+    var brushWidth = $inputBrushWidthRange.val();
+    var brushColor = brushColorpicker.getColor();
+
+    return {
+        width: brushWidth,
+        color: hexToRGBa(brushColor, 0.5)
+    };
+}
+
+function activateShapeMode() {
+    imageEditor.stopDrawingMode();
+}
+
+function activateIconMode() {
+    imageEditor.stopDrawingMode();
+}
+
+function activateTextMode() {
+    if (imageEditor.getDrawingMode() !== 'TEXT') {
+        imageEditor.stopDrawingMode();
+        imageEditor.startDrawingMode('TEXT');
+    }
+}
+
+function setTextToolbar(obj) {
+    var fontSize = obj.fontSize;
+    var fontColor = obj.fill;
+
+    $inputTextSizeRange.val(fontSize);
+    textColorpicker.setColor(fontColor);
+}
+
+function setIconToolbar(obj) {
+    var iconColor = obj.fill;
+
+    iconColorpicker.setColor(iconColor);
+}
+
+function setShapeToolbar(obj) {
+    var strokeColor, fillColor, isTransparent;
+    var colorType = $('[name="select-color-type"]:checked').val();
+
+    if (colorType === 'stroke') {
+        strokeColor = obj.stroke;
+        isTransparent = (strokeColor === 'transparent');
+
+        if (!isTransparent) {
+            shapeColorpicker.setColor(strokeColor);
+        }
+    } else if (colorType === 'fill') {
+        fillColor = obj.fill;
+        isTransparent = (fillColor === 'transparent');
+
+        if (!isTransparent) {
+            shapeColorpicker.setColor(fillColor);
+        }
+    }
+
+    $inputCheckTransparent.prop('checked', isTransparent);
+    $inputStrokeWidthRange.val(obj.strokeWith);
+}
+
+function showSubMenu(type) {
+    var index;
+
+    switch (type) {
+        case 'shape':
+            index = 3;
+            break;
+        case 'icon':
+            index = 4;
+            break;
+        case 'text':
+            index = 5;
+            break;
+        default:
+            index = 0;
+    }
+
+    $displayingSubMenu.hide();
+    $displayingHiddenMenu.hide();
+
+    $displayingSubMenu = $menuButtons.eq(index).parent().find(submenuClass).show();
+}
+
+// Bind custom event of image editor
+imageEditor.on({
+    undoStackChanged: function(length) {
+        if (length) {
+            $btnUndo.removeClass('disabled');
+        } else {
+            $btnUndo.addClass('disabled');
+        }
+    },
+    redoStackChanged: function(length) {
+        if (length) {
+            $btnRedo.removeClass('disabled');
+        } else {
+            $btnRedo.addClass('disabled');
+        }
+    },
+    objectScaled: function(obj) {
+        if (obj.type === 'text') {
+            $inputTextSizeRange.val(obj.fontSize);
+        }
+    },
+    objectActivated: function(obj) {
+        activeObjectId = obj.id;
+        if (obj.type === 'rect' || obj.type === 'circle' || obj.type === 'triangle') {
+            showSubMenu('shape');
+            setShapeToolbar(obj);
+            activateShapeMode();
+        } else if (obj.type === 'icon') {
+            showSubMenu('icon');
+            setIconToolbar(obj);
+            activateIconMode();
+        } else if (obj.type === 'text') {
+            showSubMenu('text');
+            setTextToolbar(obj);
+            activateTextMode();
+        }
+    }
+});
+
+// Image editor controls action
+$menuButtons.on('click', function() {
+    $displayingSubMenu = $(this).parent().find(submenuClass).show();
+    $displayingHiddenMenu = $(this).parent().find(hiddenmenuClass);
+});
+
+$submenuButtons.on('click', function() {
+    $displayingHiddenMenu.hide();
+    $displayingHiddenMenu = $(this).parent().find(hiddenmenuClass).show();
+});
+
+$btnShowMenu.on('click', function() {
+    $displayingSubMenu.hide();
+    $displayingHiddenMenu.hide();
+    $msg.show();
+
+    imageEditor.stopDrawingMode();
+});
+
+//Image load action
+$inputImage.on('change', function(event) {
+    var file;
+    var img;
+    var resolution;
+
+    if (!supportingFileAPI) {
+        alert('This browser does not support file-api');
+    }
+
+    file = event.target.files[0];
+
+    if (file) {
+        img = new Image();
+
+        img.onload = function() {
+            resolution = this.width * this.height;
+
+            if (resolution <= MAX_RESOLUTION) {
+                imageEditor.loadImageFromFile(file).then(() => {
+                    imageEditor.clearUndoStack();
+                });
+            } else {
+                alert('Loaded image\'s resolution is too large!\nRecommended resolution is 3264 * 2448!');
+            }
+
+            URL.revokeObjectURL(file);
+        };
+
+        img.src = URL.createObjectURL(file);
+    }
+});
+
+// Undo action
+$btnUndo.on('click', function() {
+    if (!$(this).hasClass('disabled')) {
+        imageEditor.undo();
+    }
+});
+
+// Redo action
+$btnRedo.on('click', function() {
+    if (!$(this).hasClass('disabled')) {
+        imageEditor.redo();
+    }
+});
+
+// Remove active object action
+$btnRemoveActiveObject.on('click', function() {
+    imageEditor.removeObject(activeObjectId);
+});
+
+// Download action
+$btnDownload.on('click', function() {
+    var imageName = imageEditor.getImageName();
+    var dataURL = imageEditor.toDataURL();
+    var blob, type, w;
+
+    if (supportingFileAPI) {
+        blob = base64ToBlob(dataURL);
+        type = blob.type.split('/')[1];
+        if (imageName.split('.').pop() !== type) {
+            imageName += '.' + type;
+        }
+
+        // Library: FileSaver - saveAs
+        saveAs(blob, imageName); // eslint-disable-line
+    } else {
+        alert('This browser needs a file-server');
+        w = window.open();
+        w.document.body.innerHTML = '<img src=' + dataURL + '>';
+    }
+});
+
+// Crop menu action
+$btnCrop.on('click', function() {
+    imageEditor.startDrawingMode('CROPPER');
+});
+
+$btnApplyCrop.on('click', function() {
+    imageEditor.crop(imageEditor.getCropzoneRect()).then(() => {
+        imageEditor.stopDrawingMode();
+        $subMenus.removeClass('show');
+        $hiddenMenus.removeClass('show');
+    });
+});
+
+// Orientation menu action
+$btnRotateClockwise.on('click', function() {
+    imageEditor.rotate(90);
+});
+
+$btnRotateCounterClockWise.on('click', function() {
+    imageEditor.rotate(-90);
+});
+
+$btnFlipX.on('click', function() {
+    imageEditor.flipX();
+});
+
+$btnFlipY.on('click', function() {
+    imageEditor.flipY();
+});
+
+// Icon menu action
+$btnAddArrowIcon.on('click', function() {
+    imageEditor.addIcon('arrow');
+});
+
+$btnAddCancelIcon.on('click', function() {
+    imageEditor.addIcon('cancel');
+});
+
+$btnAddCustomIcon.on('click', function() {
+    imageEditor.addIcon('customArrow');
+});
+
+iconColorpicker.on('selectColor', function(event) {
+    imageEditor.changeIconColor(activeObjectId, event.color);
+});
+
+// Text menu action
+$btnAddText.on('click', function() {
+    var initText = 'DoubleClick';
+
+    imageEditor.startDrawingMode('TEXT');
+    imageEditor.addText(initText, {
+        styles: {
+            fontSize: parseInt($inputTextSizeRange.val(), 10)
+        }
+    });
+});
+
+$btnChangeTextStyle.on('click', function() {
+    var styleType = $(this).attr('data-style-type');
+    var styleObj = {};
+    var styleObjKey;
+
+    switch (styleType) {
+        case 'bold':
+            styleObjKey = 'fontWeight';
+            break;
+        case 'italic':
+            styleObjKey = 'fontStyle';
+            break;
+        case 'underline':
+            styleObjKey = 'textDecoration';
+            break;
+        case 'left':
+            styleObjKey = 'textAlign';
+            break;
+        case 'center':
+            styleObjKey = 'textAlign';
+            break;
+        case 'right':
+            styleObjKey = 'textAlign';
+            break;
+        default:
+            styleObjKey = '';
+    }
+
+    styleObj[styleObjKey] = styleType;
+
+    imageEditor.changeTextStyle(activeObjectId, styleObj);
+});
+
+$inputTextSizeRange.on('change', function() {
+    imageEditor.changeTextStyle(activeObjectId, {
+        fontSize: parseInt($(this).val(), 10)
+    });
+});
+
+textColorpicker.on('selectColor', function(event) {
+    imageEditor.changeTextStyle(activeObjectId, {
+        fill: event.color
+    });
+});
+
+// Draw line menu action
+$btnFreeDrawing.on('click', function() {
+    var settings = getBrushSettings();
+
+    imageEditor.stopDrawingMode();
+    imageEditor.startDrawingMode('FREE_DRAWING', settings);
+});
+
+$btnLineDrawing.on('click', function() {
+    var settings = getBrushSettings();
+
+    imageEditor.stopDrawingMode();
+    imageEditor.startDrawingMode('LINE_DRAWING', settings);
+});
+
+$inputBrushWidthRange.on('change', function() {
+    imageEditor.setBrush({
+        width: parseInt($(this).val(), 10)
+    });
+});
+
+brushColorpicker.on('selectColor', function(event) {
+    imageEditor.setBrush({
+        color: hexToRGBa(event.color, 0.5)
+    });
+});
+
+// Add shape menu action
+$btnAddRect.on('click', function() {
+    imageEditor.addShape('rect', tui.util.extend({
+        width: 500,
+        height: 300
+    }, shapeOpt));
+});
+
+$btnAddSquare.on('click', function() {
+    imageEditor.addShape('rect', tui.util.extend({
+        width: 400,
+        height: 400,
+        isRegular: true
+    }, shapeOpt));
+});
+
+$btnAddEllipse.on('click', function() {
+    imageEditor.addShape('circle', tui.util.extend({
+        rx: 300,
+        ry: 200
+    }, shapeOpt));
+});
+
+$btnAddCircle.on('click', function() {
+    imageEditor.addShape('circle', tui.util.extend({
+        rx: 200,
+        ry: 200,
+        isRegular: true
+    }, shapeOpt));
+});
+
+$btnAddTriangle.on('click', function() {
+    imageEditor.addShape('triangle', tui.util.extend({
+        width: 500,
+        height: 400,
+        isRegular: true
+    }, shapeOpt));
+});
+
+$inputStrokeWidthRange.on('change', function() {
+    imageEditor.changeShape(activeObjectId, {
+        strokeWidth: parseInt($(this).val(), 10)
+    });
+});
+
+$inputCheckTransparent.on('change', function() {
+    var colorType = $('[name="select-color-type"]:checked').val();
+    var isTransparent = $(this).prop('checked');
+    var color;
+
+    if (!isTransparent) {
+        color = shapeColorpicker.getColor();
+    } else {
+        color = 'transparent';
+    }
+
+    if (colorType === 'stroke') {
+        imageEditor.changeShape(activeObjectId, {
+            stroke: color
+        });
+    } else if (colorType === 'fill') {
+        imageEditor.changeShape(activeObjectId, {
+            fill: color
+        });
+    }
+});
+
+shapeColorpicker.on('selectColor', function(event) {
+    var colorType = $('[name="select-color-type"]:checked').val();
+    var isTransparent = $inputCheckTransparent.prop('checked');
+    var color = event.color;
+
+    if (isTransparent) {
+        return;
+    }
+
+    if (colorType === 'stroke') {
+        imageEditor.changeShape(activeObjectId, {
+            stroke: color
+        });
+    } else if (colorType === 'fill') {
+        imageEditor.changeShape(activeObjectId, {
+            fill: color
+        });
+    }
+});
+
+// Load sample image
+imageEditor.loadImageFromURL('img/sampleImage.jpg', 'SampleImage').then(() => {
+    imageEditor.clearUndoStack();
+});

+ 26123 - 0
public/assets/v1/common/lib/imageEditor/libs/fabric.js

@@ -0,0 +1,26123 @@
+/* build: `node build.js modules=ALL exclude=json,gestures minifier=uglifyjs` */
+ /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
+
+var fabric = fabric || { version: "1.6.7" };
+if (typeof exports !== 'undefined') {
+  exports.fabric = fabric;
+}
+
+if (typeof document !== 'undefined' && typeof window !== 'undefined') {
+  fabric.document = document;
+  fabric.window = window;
+  // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system)
+  window.fabric = fabric;
+}
+else {
+  // assume we're running under node.js when document/window are not present
+  fabric.document = require("jsdom")
+    .jsdom("<!DOCTYPE html><html><head></head><body></body></html>");
+
+  if (fabric.document.createWindow) {
+    fabric.window = fabric.document.createWindow();
+  } else {
+    fabric.window = fabric.document.parentWindow;
+  }
+}
+
+/**
+ * True when in environment that supports touch events
+ * @type boolean
+ */
+fabric.isTouchSupported = "ontouchstart" in fabric.document.documentElement;
+
+/**
+ * True when in environment that's probably Node.js
+ * @type boolean
+ */
+fabric.isLikelyNode = typeof Buffer !== 'undefined' &&
+                      typeof window === 'undefined';
+
+/* _FROM_SVG_START_ */
+/**
+ * Attributes parsed from all SVG elements
+ * @type array
+ */
+fabric.SHARED_ATTRIBUTES = [
+  "display",
+  "transform",
+  "fill", "fill-opacity", "fill-rule",
+  "opacity",
+  "stroke", "stroke-dasharray", "stroke-linecap",
+  "stroke-linejoin", "stroke-miterlimit",
+  "stroke-opacity", "stroke-width",
+  "id"
+];
+/* _FROM_SVG_END_ */
+
+/**
+ * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion.
+ */
+fabric.DPI = 96;
+fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:e[-+]?\\d+)?)';
+fabric.fontPaths = { };
+
+/**
+ * Cache Object for widths of chars in text rendering.
+ */
+fabric.charWidthsCache = { };
+
+/**
+ * Device Pixel Ratio
+ * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html
+ */
+fabric.devicePixelRatio = fabric.window.devicePixelRatio ||
+                          fabric.window.webkitDevicePixelRatio ||
+                          fabric.window.mozDevicePixelRatio ||
+                          1;
+
+
+(function() {
+
+  /**
+   * @private
+   * @param {String} eventName
+   * @param {Function} handler
+   */
+  function _removeEventListener(eventName, handler) {
+    if (!this.__eventListeners[eventName]) {
+      return;
+    }
+    var eventListener = this.__eventListeners[eventName];
+    if (handler) {
+      eventListener[eventListener.indexOf(handler)] = false;
+    }
+    else {
+      fabric.util.array.fill(eventListener, false);
+    }
+  }
+
+  /**
+   * Observes specified event
+   * @deprecated `observe` deprecated since 0.8.34 (use `on` instead)
+   * @memberOf fabric.Observable
+   * @alias on
+   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
+   * @param {Function} handler Function that receives a notification when an event of the specified type occurs
+   * @return {Self} thisArg
+   * @chainable
+   */
+  function observe(eventName, handler) {
+    if (!this.__eventListeners) {
+      this.__eventListeners = { };
+    }
+    // one object with key/value pairs was passed
+    if (arguments.length === 1) {
+      for (var prop in eventName) {
+        this.on(prop, eventName[prop]);
+      }
+    }
+    else {
+      if (!this.__eventListeners[eventName]) {
+        this.__eventListeners[eventName] = [];
+      }
+      this.__eventListeners[eventName].push(handler);
+    }
+    return this;
+  }
+
+  /**
+   * Stops event observing for a particular event handler. Calling this method
+   * without arguments removes all handlers for all events
+   * @deprecated `stopObserving` deprecated since 0.8.34 (use `off` instead)
+   * @memberOf fabric.Observable
+   * @alias off
+   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
+   * @param {Function} handler Function to be deleted from EventListeners
+   * @return {Self} thisArg
+   * @chainable
+   */
+  function stopObserving(eventName, handler) {
+    if (!this.__eventListeners) {
+      return;
+    }
+
+    // remove all key/value pairs (event name -> event handler)
+    if (arguments.length === 0) {
+      for (eventName in this.__eventListeners) {
+        _removeEventListener.call(this, eventName);
+      }
+    }
+    // one object with key/value pairs was passed
+    else if (arguments.length === 1 && typeof arguments[0] === 'object') {
+      for (var prop in eventName) {
+        _removeEventListener.call(this, prop, eventName[prop]);
+      }
+    }
+    else {
+      _removeEventListener.call(this, eventName, handler);
+    }
+    return this;
+  }
+
+  /**
+   * Fires event with an optional options object
+   * @deprecated `fire` deprecated since 1.0.7 (use `trigger` instead)
+   * @memberOf fabric.Observable
+   * @alias trigger
+   * @param {String} eventName Event name to fire
+   * @param {Object} [options] Options object
+   * @return {Self} thisArg
+   * @chainable
+   */
+  function fire(eventName, options) {
+    if (!this.__eventListeners) {
+      return;
+    }
+
+    var listenersForEvent = this.__eventListeners[eventName];
+    if (!listenersForEvent) {
+      return;
+    }
+
+    for (var i = 0, len = listenersForEvent.length; i < len; i++) {
+      listenersForEvent[i] && listenersForEvent[i].call(this, options || { });
+    }
+    this.__eventListeners[eventName] = listenersForEvent.filter(function(value) {
+      return value !== false;
+    });
+    return this;
+  }
+
+  /**
+   * @namespace fabric.Observable
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}
+   * @see {@link http://fabricjs.com/events|Events demo}
+   */
+  fabric.Observable = {
+    observe: observe,
+    stopObserving: stopObserving,
+    fire: fire,
+
+    on: observe,
+    off: stopObserving,
+    trigger: fire
+  };
+})();
+
+
+/**
+ * @namespace fabric.Collection
+ */
+fabric.Collection = {
+
+  _objects: [],
+
+  /**
+   * Adds objects to collection, Canvas or Group, then renders canvas
+   * (if `renderOnAddRemove` is not `false`).
+   * in case of Group no changes to bounding box are made.
+   * Objects should be instances of (or inherit from) fabric.Object
+   * @param {...fabric.Object} object Zero or more fabric instances
+   * @return {Self} thisArg
+   * @chainable
+   */
+  add: function () {
+    this._objects.push.apply(this._objects, arguments);
+    if (this._onObjectAdded) {
+      for (var i = 0, length = arguments.length; i < length; i++) {
+        this._onObjectAdded(arguments[i]);
+      }
+    }
+    this.renderOnAddRemove && this.renderAll();
+    return this;
+  },
+
+  /**
+   * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)
+   * An object should be an instance of (or inherit from) fabric.Object
+   * @param {Object} object Object to insert
+   * @param {Number} index Index to insert object at
+   * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs
+   * @return {Self} thisArg
+   * @chainable
+   */
+  insertAt: function (object, index, nonSplicing) {
+    var objects = this.getObjects();
+    if (nonSplicing) {
+      objects[index] = object;
+    }
+    else {
+      objects.splice(index, 0, object);
+    }
+    this._onObjectAdded && this._onObjectAdded(object);
+    this.renderOnAddRemove && this.renderAll();
+    return this;
+  },
+
+  /**
+   * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)
+   * @param {...fabric.Object} object Zero or more fabric instances
+   * @return {Self} thisArg
+   * @chainable
+   */
+  remove: function() {
+    var objects = this.getObjects(),
+        index, somethingRemoved = false;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      index = objects.indexOf(arguments[i]);
+
+      // only call onObjectRemoved if an object was actually removed
+      if (index !== -1) {
+        somethingRemoved = true;
+        objects.splice(index, 1);
+        this._onObjectRemoved && this._onObjectRemoved(arguments[i]);
+      }
+    }
+
+    this.renderOnAddRemove && somethingRemoved && this.renderAll();
+    return this;
+  },
+
+  /**
+   * Executes given function for each object in this group
+   * @param {Function} callback
+   *                   Callback invoked with current object as first argument,
+   *                   index - as second and an array of all objects - as third.
+   *                   Callback is invoked in a context of Global Object (e.g. `window`)
+   *                   when no `context` argument is given
+   *
+   * @param {Object} context Context (aka thisObject)
+   * @return {Self} thisArg
+   * @chainable
+   */
+  forEachObject: function(callback, context) {
+    var objects = this.getObjects();
+    for (var i = 0, len = objects.length; i < len; i++) {
+      callback.call(context, objects[i], i, objects);
+    }
+    return this;
+  },
+
+  /**
+   * Returns an array of children objects of this instance
+   * Type parameter introduced in 1.3.10
+   * @param {String} [type] When specified, only objects of this type are returned
+   * @return {Array}
+   */
+  getObjects: function(type) {
+    if (typeof type === 'undefined') {
+      return this._objects;
+    }
+    return this._objects.filter(function(o) {
+      return o.type === type;
+    });
+  },
+
+  /**
+   * Returns object at specified index
+   * @param {Number} index
+   * @return {Self} thisArg
+   */
+  item: function (index) {
+    return this.getObjects()[index];
+  },
+
+  /**
+   * Returns true if collection contains no objects
+   * @return {Boolean} true if collection is empty
+   */
+  isEmpty: function () {
+    return this.getObjects().length === 0;
+  },
+
+  /**
+   * Returns a size of a collection (i.e: length of an array containing its objects)
+   * @return {Number} Collection size
+   */
+  size: function() {
+    return this.getObjects().length;
+  },
+
+  /**
+   * Returns true if collection contains an object
+   * @param {Object} object Object to check against
+   * @return {Boolean} `true` if collection contains an object
+   */
+  contains: function(object) {
+    return this.getObjects().indexOf(object) > -1;
+  },
+
+  /**
+   * Returns number representation of a collection complexity
+   * @return {Number} complexity
+   */
+  complexity: function () {
+    return this.getObjects().reduce(function (memo, current) {
+      memo += current.complexity ? current.complexity() : 0;
+      return memo;
+    }, 0);
+  }
+};
+
+
+(function(global) {
+
+  var sqrt = Math.sqrt,
+      atan2 = Math.atan2,
+      pow = Math.pow,
+      abs = Math.abs,
+      PiBy180 = Math.PI / 180;
+
+  /**
+   * @namespace fabric.util
+   */
+  fabric.util = {
+
+    /**
+     * Removes value from an array.
+     * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`
+     * @static
+     * @memberOf fabric.util
+     * @param {Array} array
+     * @param {*} value
+     * @return {Array} original array
+     */
+    removeFromArray: function(array, value) {
+      var idx = array.indexOf(value);
+      if (idx !== -1) {
+        array.splice(idx, 1);
+      }
+      return array;
+    },
+
+    /**
+     * Returns random number between 2 specified ones.
+     * @static
+     * @memberOf fabric.util
+     * @param {Number} min lower limit
+     * @param {Number} max upper limit
+     * @return {Number} random value (between min and max)
+     */
+    getRandomInt: function(min, max) {
+      return Math.floor(Math.random() * (max - min + 1)) + min;
+    },
+
+    /**
+     * Transforms degrees to radians.
+     * @static
+     * @memberOf fabric.util
+     * @param {Number} degrees value in degrees
+     * @return {Number} value in radians
+     */
+    degreesToRadians: function(degrees) {
+      return degrees * PiBy180;
+    },
+
+    /**
+     * Transforms radians to degrees.
+     * @static
+     * @memberOf fabric.util
+     * @param {Number} radians value in radians
+     * @return {Number} value in degrees
+     */
+    radiansToDegrees: function(radians) {
+      return radians / PiBy180;
+    },
+
+    /**
+     * Rotates `point` around `origin` with `radians`
+     * @static
+     * @memberOf fabric.util
+     * @param {fabric.Point} point The point to rotate
+     * @param {fabric.Point} origin The origin of the rotation
+     * @param {Number} radians The radians of the angle for the rotation
+     * @return {fabric.Point} The new rotated point
+     */
+    rotatePoint: function(point, origin, radians) {
+      point.subtractEquals(origin);
+      var v = fabric.util.rotateVector(point, radians);
+      return new fabric.Point(v.x, v.y).addEquals(origin);
+    },
+
+    /**
+     * Rotates `vector` with `radians`
+     * @static
+     * @memberOf fabric.util
+     * @param {Object} vector The vector to rotate (x and y)
+     * @param {Number} radians The radians of the angle for the rotation
+     * @return {Object} The new rotated point
+     */
+    rotateVector: function(vector, radians) {
+      var sin = Math.sin(radians),
+          cos = Math.cos(radians),
+          rx = vector.x * cos - vector.y * sin,
+          ry = vector.x * sin + vector.y * cos;
+      return {
+        x: rx,
+        y: ry
+      };
+    },
+
+    /**
+     * Apply transform t to point p
+     * @static
+     * @memberOf fabric.util
+     * @param  {fabric.Point} p The point to transform
+     * @param  {Array} t The transform
+     * @param  {Boolean} [ignoreOffset] Indicates that the offset should not be applied
+     * @return {fabric.Point} The transformed point
+     */
+    transformPoint: function(p, t, ignoreOffset) {
+      if (ignoreOffset) {
+        return new fabric.Point(
+          t[0] * p.x + t[2] * p.y,
+          t[1] * p.x + t[3] * p.y
+        );
+      }
+      return new fabric.Point(
+        t[0] * p.x + t[2] * p.y + t[4],
+        t[1] * p.x + t[3] * p.y + t[5]
+      );
+    },
+
+    /**
+     * Returns coordinates of points's bounding rectangle (left, top, width, height)
+     * @param {Array} points 4 points array
+     * @return {Object} Object with left, top, width, height properties
+     */
+    makeBoundingBoxFromPoints: function(points) {
+      var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],
+          minX = fabric.util.array.min(xPoints),
+          maxX = fabric.util.array.max(xPoints),
+          width = Math.abs(minX - maxX),
+          yPoints = [points[0].y, points[1].y, points[2].y, points[3].y],
+          minY = fabric.util.array.min(yPoints),
+          maxY = fabric.util.array.max(yPoints),
+          height = Math.abs(minY - maxY);
+
+      return {
+        left: minX,
+        top: minY,
+        width: width,
+        height: height
+      };
+    },
+
+    /**
+     * Invert transformation t
+     * @static
+     * @memberOf fabric.util
+     * @param {Array} t The transform
+     * @return {Array} The inverted transform
+     */
+    invertTransform: function(t) {
+      var a = 1 / (t[0] * t[3] - t[1] * t[2]),
+          r = [a * t[3], -a * t[1], -a * t[2], a * t[0]],
+          o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true);
+      r[4] = -o.x;
+      r[5] = -o.y;
+      return r;
+    },
+
+    /**
+     * A wrapper around Number#toFixed, which contrary to native method returns number, not string.
+     * @static
+     * @memberOf fabric.util
+     * @param {Number|String} number number to operate on
+     * @param {Number} fractionDigits number of fraction digits to "leave"
+     * @return {Number}
+     */
+    toFixed: function(number, fractionDigits) {
+      return parseFloat(Number(number).toFixed(fractionDigits));
+    },
+
+    /**
+     * Converts from attribute value to pixel value if applicable.
+     * Returns converted pixels or original value not converted.
+     * @param {Number|String} value number to operate on
+     * @param {Number} fontSize
+     * @return {Number|String}
+     */
+    parseUnit: function(value, fontSize) {
+      var unit = /\D{0,2}$/.exec(value),
+          number = parseFloat(value);
+      if (!fontSize) {
+        fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;
+      }
+      switch (unit[0]) {
+        case 'mm':
+          return number * fabric.DPI / 25.4;
+
+        case 'cm':
+          return number * fabric.DPI / 2.54;
+
+        case 'in':
+          return number * fabric.DPI;
+
+        case 'pt':
+          return number * fabric.DPI / 72; // or * 4 / 3
+
+        case 'pc':
+          return number * fabric.DPI / 72 * 12; // or * 16
+
+        case 'em':
+          return number * fontSize;
+
+        default:
+          return number;
+      }
+    },
+
+    /**
+     * Function which always returns `false`.
+     * @static
+     * @memberOf fabric.util
+     * @return {Boolean}
+     */
+    falseFunction: function() {
+      return false;
+    },
+
+    /**
+     * Returns klass "Class" object of given namespace
+     * @memberOf fabric.util
+     * @param {String} type Type of object (eg. 'circle')
+     * @param {String} namespace Namespace to get klass "Class" object from
+     * @return {Object} klass "Class"
+     */
+    getKlass: function(type, namespace) {
+      // capitalize first letter only
+      type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1));
+      return fabric.util.resolveNamespace(namespace)[type];
+    },
+
+    /**
+     * Returns object of given namespace
+     * @memberOf fabric.util
+     * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'
+     * @return {Object} Object for given namespace (default fabric)
+     */
+    resolveNamespace: function(namespace) {
+      if (!namespace) {
+        return fabric;
+      }
+
+      var parts = namespace.split('.'),
+          len = parts.length, i,
+          obj = global || fabric.window;
+
+      for (i = 0; i < len; ++i) {
+        obj = obj[parts[i]];
+      }
+
+      return obj;
+    },
+
+    /**
+     * Loads image element from given url and passes it to a callback
+     * @memberOf fabric.util
+     * @param {String} url URL representing an image
+     * @param {Function} callback Callback; invoked with loaded image
+     * @param {*} [context] Context to invoke callback in
+     * @param {Object} [crossOrigin] crossOrigin value to set image element to
+     */
+    loadImage: function(url, callback, context, crossOrigin) {
+      if (!url) {
+        callback && callback.call(context, url);
+        return;
+      }
+
+      var img = fabric.util.createImage();
+
+      /** @ignore */
+      img.onload = function () {
+        callback && callback.call(context, img);
+        img = img.onload = img.onerror = null;
+      };
+
+      /** @ignore */
+      img.onerror = function() {
+        fabric.log('Error loading ' + img.src);
+        callback && callback.call(context, null, true);
+        img = img.onload = img.onerror = null;
+      };
+
+      // data-urls appear to be buggy with crossOrigin
+      // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767
+      // see https://code.google.com/p/chromium/issues/detail?id=315152
+      //     https://bugzilla.mozilla.org/show_bug.cgi?id=935069
+      if (url.indexOf('data') !== 0 && crossOrigin) {
+        img.crossOrigin = crossOrigin;
+      }
+
+      img.src = url;
+    },
+
+    /**
+     * Creates corresponding fabric instances from their object representations
+     * @static
+     * @memberOf fabric.util
+     * @param {Array} objects Objects to enliven
+     * @param {Function} callback Callback to invoke when all objects are created
+     * @param {String} namespace Namespace to get klass "Class" object from
+     * @param {Function} reviver Method for further parsing of object elements,
+     * called after each fabric object created.
+     */
+    enlivenObjects: function(objects, callback, namespace, reviver) {
+      objects = objects || [];
+
+      function onLoaded() {
+        if (++numLoadedObjects === numTotalObjects) {
+          callback && callback(enlivenedObjects);
+        }
+      }
+
+      var enlivenedObjects = [],
+          numLoadedObjects = 0,
+          numTotalObjects = objects.length;
+
+      if (!numTotalObjects) {
+        callback && callback(enlivenedObjects);
+        return;
+      }
+
+      objects.forEach(function (o, index) {
+        // if sparse array
+        if (!o || !o.type) {
+          onLoaded();
+          return;
+        }
+        var klass = fabric.util.getKlass(o.type, namespace);
+        if (klass.async) {
+          klass.fromObject(o, function (obj, error) {
+            if (!error) {
+              enlivenedObjects[index] = obj;
+              reviver && reviver(o, enlivenedObjects[index]);
+            }
+            onLoaded();
+          });
+        }
+        else {
+          enlivenedObjects[index] = klass.fromObject(o);
+          reviver && reviver(o, enlivenedObjects[index]);
+          onLoaded();
+        }
+      });
+    },
+
+    /**
+     * Groups SVG elements (usually those retrieved from SVG document)
+     * @static
+     * @memberOf fabric.util
+     * @param {Array} elements SVG elements to group
+     * @param {Object} [options] Options object
+     * @param {String} path Value to set sourcePath to
+     * @return {fabric.Object|fabric.PathGroup}
+     */
+    groupSVGElements: function(elements, options, path) {
+      var object;
+
+      object = new fabric.PathGroup(elements, options);
+
+      if (typeof path !== 'undefined') {
+        object.setSourcePath(path);
+      }
+      return object;
+    },
+
+    /**
+     * Populates an object with properties of another object
+     * @static
+     * @memberOf fabric.util
+     * @param {Object} source Source object
+     * @param {Object} destination Destination object
+     * @return {Array} properties Propertie names to include
+     */
+    populateWithProperties: function(source, destination, properties) {
+      if (properties && Object.prototype.toString.call(properties) === '[object Array]') {
+        for (var i = 0, len = properties.length; i < len; i++) {
+          if (properties[i] in source) {
+            destination[properties[i]] = source[properties[i]];
+          }
+        }
+      }
+    },
+
+    /**
+     * Draws a dashed line between two points
+     *
+     * This method is used to draw dashed line around selection area.
+     * See <a href="http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas">dotted stroke in canvas</a>
+     *
+     * @param {CanvasRenderingContext2D} ctx context
+     * @param {Number} x  start x coordinate
+     * @param {Number} y start y coordinate
+     * @param {Number} x2 end x coordinate
+     * @param {Number} y2 end y coordinate
+     * @param {Array} da dash array pattern
+     */
+    drawDashedLine: function(ctx, x, y, x2, y2, da) {
+      var dx = x2 - x,
+          dy = y2 - y,
+          len = sqrt(dx * dx + dy * dy),
+          rot = atan2(dy, dx),
+          dc = da.length,
+          di = 0,
+          draw = true;
+
+      ctx.save();
+      ctx.translate(x, y);
+      ctx.moveTo(0, 0);
+      ctx.rotate(rot);
+
+      x = 0;
+      while (len > x) {
+        x += da[di++ % dc];
+        if (x > len) {
+          x = len;
+        }
+        ctx[draw ? 'lineTo' : 'moveTo'](x, 0);
+        draw = !draw;
+      }
+
+      ctx.restore();
+    },
+
+    /**
+     * Creates canvas element and initializes it via excanvas if necessary
+     * @static
+     * @memberOf fabric.util
+     * @param {CanvasElement} [canvasEl] optional canvas element to initialize;
+     * when not given, element is created implicitly
+     * @return {CanvasElement} initialized canvas element
+     */
+    createCanvasElement: function(canvasEl) {
+      canvasEl || (canvasEl = fabric.document.createElement('canvas'));
+      /* eslint-disable camelcase */
+      if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') {
+        G_vmlCanvasManager.initElement(canvasEl);
+      }
+      /* eslint-enable camelcase */
+      return canvasEl;
+    },
+
+    /**
+     * Creates image element (works on client and node)
+     * @static
+     * @memberOf fabric.util
+     * @return {HTMLImageElement} HTML image element
+     */
+    createImage: function() {
+      return fabric.isLikelyNode
+        ? new (require('canvas').Image)()
+        : fabric.document.createElement('img');
+    },
+
+    /**
+     * Creates accessors (getXXX, setXXX) for a "class", based on "stateProperties" array
+     * @static
+     * @memberOf fabric.util
+     * @param {Object} klass "Class" to create accessors for
+     */
+    createAccessors: function(klass) {
+      var proto = klass.prototype, i, propName,
+          capitalizedPropName, setterName, getterName;
+
+      for (i = proto.stateProperties.length; i--; ) {
+
+        propName = proto.stateProperties[i];
+        capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
+        setterName = 'set' + capitalizedPropName;
+        getterName = 'get' + capitalizedPropName;
+
+        // using `new Function` for better introspection
+        if (!proto[getterName]) {
+          proto[getterName] = (function(property) {
+            return new Function('return this.get("' + property + '")');
+          })(propName);
+        }
+        if (!proto[setterName]) {
+          proto[setterName] = (function(property) {
+            return new Function('value', 'return this.set("' + property + '", value)');
+          })(propName);
+        }
+      }
+    },
+
+    /**
+     * @static
+     * @memberOf fabric.util
+     * @param {fabric.Object} receiver Object implementing `clipTo` method
+     * @param {CanvasRenderingContext2D} ctx Context to clip
+     */
+    clipContext: function(receiver, ctx) {
+      ctx.save();
+      ctx.beginPath();
+      receiver.clipTo(ctx);
+      ctx.clip();
+    },
+
+    /**
+     * Multiply matrix A by matrix B to nest transformations
+     * @static
+     * @memberOf fabric.util
+     * @param  {Array} a First transformMatrix
+     * @param  {Array} b Second transformMatrix
+     * @param  {Boolean} is2x2 flag to multiply matrices as 2x2 matrices
+     * @return {Array} The product of the two transform matrices
+     */
+    multiplyTransformMatrices: function(a, b, is2x2) {
+      // Matrix multiply a * b
+      return [
+        a[0] * b[0] + a[2] * b[1],
+        a[1] * b[0] + a[3] * b[1],
+        a[0] * b[2] + a[2] * b[3],
+        a[1] * b[2] + a[3] * b[3],
+        is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4],
+        is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5]
+      ];
+    },
+
+    /**
+     * Decomposes standard 2x2 matrix into transform componentes
+     * @static
+     * @memberOf fabric.util
+     * @param  {Array} a transformMatrix
+     * @return {Object} Components of transform
+     */
+    qrDecompose: function(a) {
+      var angle = atan2(a[1], a[0]),
+          denom = pow(a[0], 2) + pow(a[1], 2),
+          scaleX = sqrt(denom),
+          scaleY = (a[0] * a[3] - a[2] * a [1]) / scaleX,
+          skewX = atan2(a[0] * a[2] + a[1] * a [3], denom);
+      return {
+        angle: angle  / PiBy180,
+        scaleX: scaleX,
+        scaleY: scaleY,
+        skewX: skewX / PiBy180,
+        skewY: 0,
+        translateX: a[4],
+        translateY: a[5]
+      };
+    },
+
+    customTransformMatrix: function(scaleX, scaleY, skewX) {
+      var skewMatrixX = [1, 0, abs(Math.tan(skewX * PiBy180)), 1],
+          scaleMatrix = [abs(scaleX), 0, 0, abs(scaleY)];
+      return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
+    },
+
+    resetObjectTransform: function (target) {
+      target.scaleX = 1;
+      target.scaleY = 1;
+      target.skewX = 0;
+      target.skewY = 0;
+      target.flipX = false;
+      target.flipY = false;
+      target.setAngle(0);
+    },
+
+    /**
+     * Returns string representation of function body
+     * @param {Function} fn Function to get body of
+     * @return {String} Function body
+     */
+    getFunctionBody: function(fn) {
+      return (String(fn).match(/function[^{]*\{([\s\S]*)\}/) || {})[1];
+    },
+
+    /**
+     * Returns true if context has transparent pixel
+     * at specified location (taking tolerance into account)
+     * @param {CanvasRenderingContext2D} ctx context
+     * @param {Number} x x coordinate
+     * @param {Number} y y coordinate
+     * @param {Number} tolerance Tolerance
+     */
+    isTransparent: function(ctx, x, y, tolerance) {
+
+      // If tolerance is > 0 adjust start coords to take into account.
+      // If moves off Canvas fix to 0
+      if (tolerance > 0) {
+        if (x > tolerance) {
+          x -= tolerance;
+        }
+        else {
+          x = 0;
+        }
+        if (y > tolerance) {
+          y -= tolerance;
+        }
+        else {
+          y = 0;
+        }
+      }
+
+      var _isTransparent = true, i, temp,
+          imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1),
+          l = imageData.data.length;
+
+      // Split image data - for tolerance > 1, pixelDataSize = 4;
+      for (i = 3; i < l; i += 4) {
+        temp = imageData.data[i];
+        _isTransparent = temp <= 0;
+        if (_isTransparent === false) {
+          break; // Stop if colour found
+        }
+      }
+
+      imageData = null;
+
+      return _isTransparent;
+    },
+
+    /**
+     * Parse preserveAspectRatio attribute from element
+     * @param {string} attribute to be parsed
+     * @return {Object} an object containing align and meetOrSlice attribute
+     */
+    parsePreserveAspectRatioAttribute: function(attribute) {
+      var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid',
+          aspectRatioAttrs = attribute.split(' '), align;
+
+      if (aspectRatioAttrs && aspectRatioAttrs.length) {
+        meetOrSlice = aspectRatioAttrs.pop();
+        if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') {
+          align = meetOrSlice;
+          meetOrSlice = 'meet';
+        }
+        else if (aspectRatioAttrs.length) {
+          align = aspectRatioAttrs.pop();
+        }
+      }
+      //divide align in alignX and alignY
+      alignX = align !== 'none' ? align.slice(1, 4) : 'none';
+      alignY = align !== 'none' ? align.slice(5, 8) : 'none';
+      return {
+        meetOrSlice: meetOrSlice,
+        alignX: alignX,
+        alignY: alignY
+      };
+    },
+
+    /**
+     * Clear char widths cache for a font family.
+     * @memberOf fabric.util
+     * @param {String} [fontFamily] font family to clear
+     */
+    clearFabricFontCache: function(fontFamily) {
+      if (!fontFamily) {
+        fabric.charWidthsCache = { };
+      }
+      else if (fabric.charWidthsCache[fontFamily]) {
+        delete fabric.charWidthsCache[fontFamily];
+      }
+    }
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function() {
+
+  var arcToSegmentsCache = { },
+      segmentToBezierCache = { },
+      boundsOfCurveCache = { },
+      _join = Array.prototype.join;
+
+  /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp
+   * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here
+   * http://mozilla.org/MPL/2.0/
+   */
+  function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {
+    var argsString = _join.call(arguments);
+    if (arcToSegmentsCache[argsString]) {
+      return arcToSegmentsCache[argsString];
+    }
+
+    var PI = Math.PI, th = rotateX * PI / 180,
+        sinTh = Math.sin(th),
+        cosTh = Math.cos(th),
+        fromX = 0, fromY = 0;
+
+    rx = Math.abs(rx);
+    ry = Math.abs(ry);
+
+    var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5,
+        py = -cosTh * toY * 0.5 + sinTh * toX * 0.5,
+        rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,
+        pl = rx2 * ry2 - rx2 * py2 - ry2 * px2,
+        root = 0;
+
+    if (pl < 0) {
+      var s = Math.sqrt(1 - pl / (rx2 * ry2));
+      rx *= s;
+      ry *= s;
+    }
+    else {
+      root = (large === sweep ? -1.0 : 1.0) *
+              Math.sqrt( pl / (rx2 * py2 + ry2 * px2));
+    }
+
+    var cx = root * rx * py / ry,
+        cy = -root * ry * px / rx,
+        cx1 = cosTh * cx - sinTh * cy + toX * 0.5,
+        cy1 = sinTh * cx + cosTh * cy + toY * 0.5,
+        mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),
+        dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry);
+
+    if (sweep === 0 && dtheta > 0) {
+      dtheta -= 2 * PI;
+    }
+    else if (sweep === 1 && dtheta < 0) {
+      dtheta += 2 * PI;
+    }
+
+    // Convert into cubic bezier segments <= 90deg
+    var segments = Math.ceil(Math.abs(dtheta / PI * 2)),
+        result = [], mDelta = dtheta / segments,
+        mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),
+        th3 = mTheta + mDelta;
+
+    for (var i = 0; i < segments; i++) {
+      result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);
+      fromX = result[i][4];
+      fromY = result[i][5];
+      mTheta = th3;
+      th3 += mDelta;
+    }
+    arcToSegmentsCache[argsString] = result;
+    return result;
+  }
+
+  function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {
+    var argsString2 = _join.call(arguments);
+    if (segmentToBezierCache[argsString2]) {
+      return segmentToBezierCache[argsString2];
+    }
+
+    var costh2 = Math.cos(th2),
+        sinth2 = Math.sin(th2),
+        costh3 = Math.cos(th3),
+        sinth3 = Math.sin(th3),
+        toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,
+        toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,
+        cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2),
+        cp1Y = fromY + mT * ( -sinTh * rx * sinth2 + cosTh * ry * costh2),
+        cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),
+        cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);
+
+    segmentToBezierCache[argsString2] = [
+      cp1X, cp1Y,
+      cp2X, cp2Y,
+      toX, toY
+    ];
+    return segmentToBezierCache[argsString2];
+  }
+
+  /*
+   * Private
+   */
+  function calcVectorAngle(ux, uy, vx, vy) {
+    var ta = Math.atan2(uy, ux),
+        tb = Math.atan2(vy, vx);
+    if (tb >= ta) {
+      return tb - ta;
+    }
+    else {
+      return 2 * Math.PI - (ta - tb);
+    }
+  }
+
+  /**
+   * Draws arc
+   * @param {CanvasRenderingContext2D} ctx
+   * @param {Number} fx
+   * @param {Number} fy
+   * @param {Array} coords
+   */
+  fabric.util.drawArc = function(ctx, fx, fy, coords) {
+    var rx = coords[0],
+        ry = coords[1],
+        rot = coords[2],
+        large = coords[3],
+        sweep = coords[4],
+        tx = coords[5],
+        ty = coords[6],
+        segs = [[], [], [], []],
+        segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);
+
+    for (var i = 0, len = segsNorm.length; i < len; i++) {
+      segs[i][0] = segsNorm[i][0] + fx;
+      segs[i][1] = segsNorm[i][1] + fy;
+      segs[i][2] = segsNorm[i][2] + fx;
+      segs[i][3] = segsNorm[i][3] + fy;
+      segs[i][4] = segsNorm[i][4] + fx;
+      segs[i][5] = segsNorm[i][5] + fy;
+      ctx.bezierCurveTo.apply(ctx, segs[i]);
+    }
+  };
+
+  /**
+   * Calculate bounding box of a elliptic-arc
+   * @param {Number} fx start point of arc
+   * @param {Number} fy
+   * @param {Number} rx horizontal radius
+   * @param {Number} ry vertical radius
+   * @param {Number} rot angle of horizontal axe
+   * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points
+   * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction
+   * @param {Number} tx end point of arc
+   * @param {Number} ty
+   */
+  fabric.util.getBoundsOfArc = function(fx, fy, rx, ry, rot, large, sweep, tx, ty) {
+
+    var fromX = 0, fromY = 0, bound, bounds = [],
+        segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);
+
+    for (var i = 0, len = segs.length; i < len; i++) {
+      bound = getBoundsOfCurve(fromX, fromY, segs[i][0], segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5]);
+      bounds.push({ x: bound[0].x + fx, y: bound[0].y + fy });
+      bounds.push({ x: bound[1].x + fx, y: bound[1].y + fy });
+      fromX = segs[i][4];
+      fromY = segs[i][5];
+    }
+    return bounds;
+  };
+
+  /**
+   * Calculate bounding box of a beziercurve
+   * @param {Number} x0 starting point
+   * @param {Number} y0
+   * @param {Number} x1 first control point
+   * @param {Number} y1
+   * @param {Number} x2 secondo control point
+   * @param {Number} y2
+   * @param {Number} x3 end of beizer
+   * @param {Number} y3
+   */
+  // taken from http://jsbin.com/ivomiq/56/edit  no credits available for that.
+  function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {
+    var argsString = _join.call(arguments);
+    if (boundsOfCurveCache[argsString]) {
+      return boundsOfCurveCache[argsString];
+    }
+
+    var sqrt = Math.sqrt,
+        min = Math.min, max = Math.max,
+        abs = Math.abs, tvalues = [],
+        bounds = [[], []],
+        a, b, c, t, t1, t2, b2ac, sqrtb2ac;
+
+    b = 6 * x0 - 12 * x1 + 6 * x2;
+    a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
+    c = 3 * x1 - 3 * x0;
+
+    for (var i = 0; i < 2; ++i) {
+      if (i > 0) {
+        b = 6 * y0 - 12 * y1 + 6 * y2;
+        a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
+        c = 3 * y1 - 3 * y0;
+      }
+
+      if (abs(a) < 1e-12) {
+        if (abs(b) < 1e-12) {
+          continue;
+        }
+        t = -c / b;
+        if (0 < t && t < 1) {
+          tvalues.push(t);
+        }
+        continue;
+      }
+      b2ac = b * b - 4 * c * a;
+      if (b2ac < 0) {
+        continue;
+      }
+      sqrtb2ac = sqrt(b2ac);
+      t1 = (-b + sqrtb2ac) / (2 * a);
+      if (0 < t1 && t1 < 1) {
+        tvalues.push(t1);
+      }
+      t2 = (-b - sqrtb2ac) / (2 * a);
+      if (0 < t2 && t2 < 1) {
+        tvalues.push(t2);
+      }
+    }
+
+    var x, y, j = tvalues.length, jlen = j, mt;
+    while (j--) {
+      t = tvalues[j];
+      mt = 1 - t;
+      x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
+      bounds[0][j] = x;
+
+      y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
+      bounds[1][j] = y;
+    }
+
+    bounds[0][jlen] = x0;
+    bounds[1][jlen] = y0;
+    bounds[0][jlen + 1] = x3;
+    bounds[1][jlen + 1] = y3;
+    var result = [
+      {
+        x: min.apply(null, bounds[0]),
+        y: min.apply(null, bounds[1])
+      },
+      {
+        x: max.apply(null, bounds[0]),
+        y: max.apply(null, bounds[1])
+      }
+    ];
+    boundsOfCurveCache[argsString] = result;
+    return result;
+  }
+
+  fabric.util.getBoundsOfCurve = getBoundsOfCurve;
+
+})();
+
+
+(function() {
+
+  var slice = Array.prototype.slice;
+
+  /* _ES5_COMPAT_START_ */
+
+  if (!Array.prototype.indexOf) {
+    /**
+     * Finds index of an element in an array
+     * @param {*} searchElement
+     * @return {Number}
+     */
+    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
+      if (this === void 0 || this === null) {
+        throw new TypeError();
+      }
+      var t = Object(this), len = t.length >>> 0;
+      if (len === 0) {
+        return -1;
+      }
+      var n = 0;
+      if (arguments.length > 0) {
+        n = Number(arguments[1]);
+        if (n !== n) { // shortcut for verifying if it's NaN
+          n = 0;
+        }
+        else if (n !== 0 && n !== Number.POSITIVE_INFINITY && n !== Number.NEGATIVE_INFINITY) {
+          n = (n > 0 || -1) * Math.floor(Math.abs(n));
+        }
+      }
+      if (n >= len) {
+        return -1;
+      }
+      var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
+      for (; k < len; k++) {
+        if (k in t && t[k] === searchElement) {
+          return k;
+        }
+      }
+      return -1;
+    };
+  }
+
+  if (!Array.prototype.forEach) {
+    /**
+     * Iterates an array, invoking callback for each element
+     * @param {Function} fn Callback to invoke for each element
+     * @param {Object} [context] Context to invoke callback in
+     * @return {Array}
+     */
+    Array.prototype.forEach = function(fn, context) {
+      for (var i = 0, len = this.length >>> 0; i < len; i++) {
+        if (i in this) {
+          fn.call(context, this[i], i, this);
+        }
+      }
+    };
+  }
+
+  if (!Array.prototype.map) {
+    /**
+     * Returns a result of iterating over an array, invoking callback for each element
+     * @param {Function} fn Callback to invoke for each element
+     * @param {Object} [context] Context to invoke callback in
+     * @return {Array}
+     */
+    Array.prototype.map = function(fn, context) {
+      var result = [];
+      for (var i = 0, len = this.length >>> 0; i < len; i++) {
+        if (i in this) {
+          result[i] = fn.call(context, this[i], i, this);
+        }
+      }
+      return result;
+    };
+  }
+
+  if (!Array.prototype.every) {
+    /**
+     * Returns true if a callback returns truthy value for all elements in an array
+     * @param {Function} fn Callback to invoke for each element
+     * @param {Object} [context] Context to invoke callback in
+     * @return {Boolean}
+     */
+    Array.prototype.every = function(fn, context) {
+      for (var i = 0, len = this.length >>> 0; i < len; i++) {
+        if (i in this && !fn.call(context, this[i], i, this)) {
+          return false;
+        }
+      }
+      return true;
+    };
+  }
+
+  if (!Array.prototype.some) {
+    /**
+     * Returns true if a callback returns truthy value for at least one element in an array
+     * @param {Function} fn Callback to invoke for each element
+     * @param {Object} [context] Context to invoke callback in
+     * @return {Boolean}
+     */
+    Array.prototype.some = function(fn, context) {
+      for (var i = 0, len = this.length >>> 0; i < len; i++) {
+        if (i in this && fn.call(context, this[i], i, this)) {
+          return true;
+        }
+      }
+      return false;
+    };
+  }
+
+  if (!Array.prototype.filter) {
+    /**
+     * Returns the result of iterating over elements in an array
+     * @param {Function} fn Callback to invoke for each element
+     * @param {Object} [context] Context to invoke callback in
+     * @return {Array}
+     */
+    Array.prototype.filter = function(fn, context) {
+      var result = [], val;
+      for (var i = 0, len = this.length >>> 0; i < len; i++) {
+        if (i in this) {
+          val = this[i]; // in case fn mutates this
+          if (fn.call(context, val, i, this)) {
+            result.push(val);
+          }
+        }
+      }
+      return result;
+    };
+  }
+
+  if (!Array.prototype.reduce) {
+    /**
+     * Returns "folded" (reduced) result of iterating over elements in an array
+     * @param {Function} fn Callback to invoke for each element
+     * @return {*}
+     */
+    Array.prototype.reduce = function(fn /*, initial*/) {
+      var len = this.length >>> 0,
+          i = 0,
+          rv;
+
+      if (arguments.length > 1) {
+        rv = arguments[1];
+      }
+      else {
+        do {
+          if (i in this) {
+            rv = this[i++];
+            break;
+          }
+          // if array contains no values, no initial value to return
+          if (++i >= len) {
+            throw new TypeError();
+          }
+        }
+        while (true);
+      }
+      for (; i < len; i++) {
+        if (i in this) {
+          rv = fn.call(null, rv, this[i], i, this);
+        }
+      }
+      return rv;
+    };
+  }
+
+  /* _ES5_COMPAT_END_ */
+
+  /**
+   * Invokes method on all items in a given array
+   * @memberOf fabric.util.array
+   * @param {Array} array Array to iterate over
+   * @param {String} method Name of a method to invoke
+   * @return {Array}
+   */
+  function invoke(array, method) {
+    var args = slice.call(arguments, 2), result = [];
+    for (var i = 0, len = array.length; i < len; i++) {
+      result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);
+    }
+    return result;
+  }
+
+  /**
+   * Finds maximum value in array (not necessarily "first" one)
+   * @memberOf fabric.util.array
+   * @param {Array} array Array to iterate over
+   * @param {String} byProperty
+   * @return {*}
+   */
+  function max(array, byProperty) {
+    return find(array, byProperty, function(value1, value2) {
+      return value1 >= value2;
+    });
+  }
+
+  /**
+   * Finds minimum value in array (not necessarily "first" one)
+   * @memberOf fabric.util.array
+   * @param {Array} array Array to iterate over
+   * @param {String} byProperty
+   * @return {*}
+   */
+  function min(array, byProperty) {
+    return find(array, byProperty, function(value1, value2) {
+      return value1 < value2;
+    });
+  }
+
+  /**
+   * @private
+   */
+  function fill(array, value) {
+    var k = array.length;
+    while (k--) {
+      array[k] = value;
+    }
+    return array;
+  }
+
+  /**
+   * @private
+   */
+  function find(array, byProperty, condition) {
+    if (!array || array.length === 0) {
+      return;
+    }
+
+    var i = array.length - 1,
+        result = byProperty ? array[i][byProperty] : array[i];
+    if (byProperty) {
+      while (i--) {
+        if (condition(array[i][byProperty], result)) {
+          result = array[i][byProperty];
+        }
+      }
+    }
+    else {
+      while (i--) {
+        if (condition(array[i], result)) {
+          result = array[i];
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * @namespace fabric.util.array
+   */
+  fabric.util.array = {
+    fill: fill,
+    invoke: invoke,
+    min: min,
+    max: max
+  };
+
+})();
+
+
+(function() {
+  /**
+   * Copies all enumerable properties of one object to another
+   * @memberOf fabric.util.object
+   * @param {Object} destination Where to copy to
+   * @param {Object} source Where to copy from
+   * @return {Object}
+   */
+
+  function extend(destination, source, deep) {
+    // JScript DontEnum bug is not taken care of
+    // the deep clone is for internal use, is not meant to avoid
+    // javascript traps or cloning html element or self referenced objects.
+    if (deep) {
+      if (!fabric.isLikelyNode && source instanceof Element) {
+        // avoid cloning deep images, canvases,
+        destination = source;
+      }
+      else if (source instanceof Array) {
+        destination = source.map(function(v) {
+          return clone(v, deep)
+        })
+      }
+      else if (source instanceof Object) {
+        for (var property in source) {
+          destination[property] = clone(source[property], deep)
+        }
+      }
+      else {
+        // this sounds odd for an extend but is ok for recursive use
+        destination = source;
+      }
+    }
+    else {
+      for (var property in source) {
+        destination[property] = source[property];
+      }
+    }
+    return destination;
+  }
+
+  /**
+   * Creates an empty object and copies all enumerable properties of another object to it
+   * @memberOf fabric.util.object
+   * @param {Object} object Object to clone
+   * @return {Object}
+   */
+  function clone(object, deep) {
+    return extend({ }, object, deep);
+  }
+
+  /** @namespace fabric.util.object */
+  fabric.util.object = {
+    extend: extend,
+    clone: clone
+  };
+
+})();
+
+
+(function() {
+
+  /* _ES5_COMPAT_START_ */
+  if (!String.prototype.trim) {
+    /**
+     * Trims a string (removing whitespace from the beginning and the end)
+     * @function external:String#trim
+     * @see <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim">String#trim on MDN</a>
+     */
+    String.prototype.trim = function () {
+      // this trim is not fully ES3 or ES5 compliant, but it should cover most cases for now
+      return this.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '');
+    };
+  }
+  /* _ES5_COMPAT_END_ */
+
+  /**
+   * Camelizes a string
+   * @memberOf fabric.util.string
+   * @param {String} string String to camelize
+   * @return {String} Camelized version of a string
+   */
+  function camelize(string) {
+    return string.replace(/-+(.)?/g, function(match, character) {
+      return character ? character.toUpperCase() : '';
+    });
+  }
+
+  /**
+   * Capitalizes a string
+   * @memberOf fabric.util.string
+   * @param {String} string String to capitalize
+   * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
+   * and other letters stay untouched, if false first letter is capitalized
+   * and other letters are converted to lowercase.
+   * @return {String} Capitalized version of a string
+   */
+  function capitalize(string, firstLetterOnly) {
+    return string.charAt(0).toUpperCase() +
+      (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase());
+  }
+
+  /**
+   * Escapes XML in a string
+   * @memberOf fabric.util.string
+   * @param {String} string String to escape
+   * @return {String} Escaped version of a string
+   */
+  function escapeXml(string) {
+    return string.replace(/&/g, '&amp;')
+       .replace(/"/g, '&quot;')
+       .replace(/'/g, '&apos;')
+       .replace(/</g, '&lt;')
+       .replace(/>/g, '&gt;');
+  }
+
+  /**
+   * String utilities
+   * @namespace fabric.util.string
+   */
+  fabric.util.string = {
+    camelize: camelize,
+    capitalize: capitalize,
+    escapeXml: escapeXml
+  };
+})();
+
+
+/* _ES5_COMPAT_START_ */
+(function() {
+
+  var slice = Array.prototype.slice,
+      apply = Function.prototype.apply,
+      Dummy = function() { };
+
+  if (!Function.prototype.bind) {
+    /**
+     * Cross-browser approximation of ES5 Function.prototype.bind (not fully spec conforming)
+     * @see <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind">Function#bind on MDN</a>
+     * @param {Object} thisArg Object to bind function to
+     * @param {Any[]} Values to pass to a bound function
+     * @return {Function}
+     */
+    Function.prototype.bind = function(thisArg) {
+      var _this = this, args = slice.call(arguments, 1), bound;
+      if (args.length) {
+        bound = function() {
+          return apply.call(_this, this instanceof Dummy ? this : thisArg, args.concat(slice.call(arguments)));
+        };
+      }
+      else {
+        /** @ignore */
+        bound = function() {
+          return apply.call(_this, this instanceof Dummy ? this : thisArg, arguments);
+        };
+      }
+      Dummy.prototype = this.prototype;
+      bound.prototype = new Dummy();
+
+      return bound;
+    };
+  }
+
+})();
+/* _ES5_COMPAT_END_ */
+
+
+(function() {
+
+  var slice = Array.prototype.slice, emptyFunction = function() { },
+
+      IS_DONTENUM_BUGGY = (function() {
+        for (var p in { toString: 1 }) {
+          if (p === 'toString') {
+            return false;
+          }
+        }
+        return true;
+      })(),
+
+      /** @ignore */
+      addMethods = function(klass, source, parent) {
+        for (var property in source) {
+
+          if (property in klass.prototype &&
+              typeof klass.prototype[property] === 'function' &&
+              (source[property] + '').indexOf('callSuper') > -1) {
+
+            klass.prototype[property] = (function(property) {
+              return function() {
+
+                var superclass = this.constructor.superclass;
+                this.constructor.superclass = parent;
+                var returnValue = source[property].apply(this, arguments);
+                this.constructor.superclass = superclass;
+
+                if (property !== 'initialize') {
+                  return returnValue;
+                }
+              };
+            })(property);
+          }
+          else {
+            klass.prototype[property] = source[property];
+          }
+
+          if (IS_DONTENUM_BUGGY) {
+            if (source.toString !== Object.prototype.toString) {
+              klass.prototype.toString = source.toString;
+            }
+            if (source.valueOf !== Object.prototype.valueOf) {
+              klass.prototype.valueOf = source.valueOf;
+            }
+          }
+        }
+      };
+
+  function Subclass() { }
+
+  function callSuper(methodName) {
+    var fn = this.constructor.superclass.prototype[methodName];
+    return (arguments.length > 1)
+      ? fn.apply(this, slice.call(arguments, 1))
+      : fn.call(this);
+  }
+
+  /**
+   * Helper for creation of "classes".
+   * @memberOf fabric.util
+   * @param {Function} [parent] optional "Class" to inherit from
+   * @param {Object} [properties] Properties shared by all instances of this class
+   *                  (be careful modifying objects defined here as this would affect all instances)
+   */
+  function createClass() {
+    var parent = null,
+        properties = slice.call(arguments, 0);
+
+    if (typeof properties[0] === 'function') {
+      parent = properties.shift();
+    }
+    function klass() {
+      this.initialize.apply(this, arguments);
+    }
+
+    klass.superclass = parent;
+    klass.subclasses = [];
+
+    if (parent) {
+      Subclass.prototype = parent.prototype;
+      klass.prototype = new Subclass();
+      parent.subclasses.push(klass);
+    }
+    for (var i = 0, length = properties.length; i < length; i++) {
+      addMethods(klass, properties[i], parent);
+    }
+    if (!klass.prototype.initialize) {
+      klass.prototype.initialize = emptyFunction;
+    }
+    klass.prototype.constructor = klass;
+    klass.prototype.callSuper = callSuper;
+    return klass;
+  }
+
+  fabric.util.createClass = createClass;
+})();
+
+
+(function () {
+
+  var unknown = 'unknown';
+
+  /* EVENT HANDLING */
+
+  function areHostMethods(object) {
+    var methodNames = Array.prototype.slice.call(arguments, 1),
+        t, i, len = methodNames.length;
+    for (i = 0; i < len; i++) {
+      t = typeof object[methodNames[i]];
+      if (!(/^(?:function|object|unknown)$/).test(t)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /** @ignore */
+  var getElement,
+      setElement,
+      getUniqueId = (function () {
+        var uid = 0;
+        return function (element) {
+          return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uid++);
+        };
+      })();
+
+  (function () {
+    var elements = { };
+    /** @ignore */
+    getElement = function (uid) {
+      return elements[uid];
+    };
+    /** @ignore */
+    setElement = function (uid, element) {
+      elements[uid] = element;
+    };
+  })();
+
+  function createListener(uid, handler) {
+    return {
+      handler: handler,
+      wrappedHandler: createWrappedHandler(uid, handler)
+    };
+  }
+
+  function createWrappedHandler(uid, handler) {
+    return function (e) {
+      handler.call(getElement(uid), e || fabric.window.event);
+    };
+  }
+
+  function createDispatcher(uid, eventName) {
+    return function (e) {
+      if (handlers[uid] && handlers[uid][eventName]) {
+        var handlersForEvent = handlers[uid][eventName];
+        for (var i = 0, len = handlersForEvent.length; i < len; i++) {
+          handlersForEvent[i].call(this, e || fabric.window.event);
+        }
+      }
+    };
+  }
+
+  var shouldUseAddListenerRemoveListener = (
+        areHostMethods(fabric.document.documentElement, 'addEventListener', 'removeEventListener') &&
+        areHostMethods(fabric.window, 'addEventListener', 'removeEventListener')),
+
+      shouldUseAttachEventDetachEvent = (
+        areHostMethods(fabric.document.documentElement, 'attachEvent', 'detachEvent') &&
+        areHostMethods(fabric.window, 'attachEvent', 'detachEvent')),
+
+      // IE branch
+      listeners = { },
+
+      // DOM L0 branch
+      handlers = { },
+
+      addListener, removeListener;
+
+  if (shouldUseAddListenerRemoveListener) {
+    /** @ignore */
+    addListener = function (element, eventName, handler) {
+      element.addEventListener(eventName, handler, false);
+    };
+    /** @ignore */
+    removeListener = function (element, eventName, handler) {
+      element.removeEventListener(eventName, handler, false);
+    };
+  }
+
+  else if (shouldUseAttachEventDetachEvent) {
+    /** @ignore */
+    addListener = function (element, eventName, handler) {
+      var uid = getUniqueId(element);
+      setElement(uid, element);
+      if (!listeners[uid]) {
+        listeners[uid] = { };
+      }
+      if (!listeners[uid][eventName]) {
+        listeners[uid][eventName] = [];
+
+      }
+      var listener = createListener(uid, handler);
+      listeners[uid][eventName].push(listener);
+      element.attachEvent('on' + eventName, listener.wrappedHandler);
+    };
+    /** @ignore */
+    removeListener = function (element, eventName, handler) {
+      var uid = getUniqueId(element), listener;
+      if (listeners[uid] && listeners[uid][eventName]) {
+        for (var i = 0, len = listeners[uid][eventName].length; i < len; i++) {
+          listener = listeners[uid][eventName][i];
+          if (listener && listener.handler === handler) {
+            element.detachEvent('on' + eventName, listener.wrappedHandler);
+            listeners[uid][eventName][i] = null;
+          }
+        }
+      }
+    };
+  }
+  else {
+    /** @ignore */
+    addListener = function (element, eventName, handler) {
+      var uid = getUniqueId(element);
+      if (!handlers[uid]) {
+        handlers[uid] = { };
+      }
+      if (!handlers[uid][eventName]) {
+        handlers[uid][eventName] = [];
+        var existingHandler = element['on' + eventName];
+        if (existingHandler) {
+          handlers[uid][eventName].push(existingHandler);
+        }
+        element['on' + eventName] = createDispatcher(uid, eventName);
+      }
+      handlers[uid][eventName].push(handler);
+    };
+    /** @ignore */
+    removeListener = function (element, eventName, handler) {
+      var uid = getUniqueId(element);
+      if (handlers[uid] && handlers[uid][eventName]) {
+        var handlersForEvent = handlers[uid][eventName];
+        for (var i = 0, len = handlersForEvent.length; i < len; i++) {
+          if (handlersForEvent[i] === handler) {
+            handlersForEvent.splice(i, 1);
+          }
+        }
+      }
+    };
+  }
+
+  /**
+   * Adds an event listener to an element
+   * @function
+   * @memberOf fabric.util
+   * @param {HTMLElement} element
+   * @param {String} eventName
+   * @param {Function} handler
+   */
+  fabric.util.addListener = addListener;
+
+  /**
+   * Removes an event listener from an element
+   * @function
+   * @memberOf fabric.util
+   * @param {HTMLElement} element
+   * @param {String} eventName
+   * @param {Function} handler
+   */
+  fabric.util.removeListener = removeListener;
+
+  /**
+   * Cross-browser wrapper for getting event's coordinates
+   * @memberOf fabric.util
+   * @param {Event} event Event object
+   */
+  function getPointer(event) {
+    event || (event = fabric.window.event);
+
+    var element = event.target ||
+                  (typeof event.srcElement !== unknown ? event.srcElement : null),
+
+        scroll = fabric.util.getScrollLeftTop(element);
+
+    return {
+      x: pointerX(event) + scroll.left,
+      y: pointerY(event) + scroll.top
+    };
+  }
+
+  var pointerX = function(event) {
+    // looks like in IE (<9) clientX at certain point (apparently when mouseup fires on VML element)
+    // is represented as COM object, with all the consequences, like "unknown" type and error on [[Get]]
+    // need to investigate later
+        return (typeof event.clientX !== unknown ? event.clientX : 0);
+      },
+
+      pointerY = function(event) {
+        return (typeof event.clientY !== unknown ? event.clientY : 0);
+      };
+
+  function _getPointer(event, pageProp, clientProp) {
+    var touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches';
+
+    return (event[touchProp] && event[touchProp][0]
+      ? (event[touchProp][0][pageProp] - (event[touchProp][0][pageProp] - event[touchProp][0][clientProp]))
+        || event[clientProp]
+      : event[clientProp]);
+  }
+
+  if (fabric.isTouchSupported) {
+    pointerX = function(event) {
+      return _getPointer(event, 'pageX', 'clientX');
+    };
+    pointerY = function(event) {
+      return _getPointer(event, 'pageY', 'clientY');
+    };
+  }
+
+  fabric.util.getPointer = getPointer;
+
+  fabric.util.object.extend(fabric.util, fabric.Observable);
+
+})();
+
+
+(function () {
+
+  /**
+   * Cross-browser wrapper for setting element's style
+   * @memberOf fabric.util
+   * @param {HTMLElement} element
+   * @param {Object} styles
+   * @return {HTMLElement} Element that was passed as a first argument
+   */
+  function setStyle(element, styles) {
+    var elementStyle = element.style;
+    if (!elementStyle) {
+      return element;
+    }
+    if (typeof styles === 'string') {
+      element.style.cssText += ';' + styles;
+      return styles.indexOf('opacity') > -1
+        ? setOpacity(element, styles.match(/opacity:\s*(\d?\.?\d*)/)[1])
+        : element;
+    }
+    for (var property in styles) {
+      if (property === 'opacity') {
+        setOpacity(element, styles[property]);
+      }
+      else {
+        var normalizedProperty = (property === 'float' || property === 'cssFloat')
+          ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat')
+          : property;
+        elementStyle[normalizedProperty] = styles[property];
+      }
+    }
+    return element;
+  }
+
+  var parseEl = fabric.document.createElement('div'),
+      supportsOpacity = typeof parseEl.style.opacity === 'string',
+      supportsFilters = typeof parseEl.style.filter === 'string',
+      reOpacity = /alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/,
+
+      /** @ignore */
+      setOpacity = function (element) { return element; };
+
+  if (supportsOpacity) {
+    /** @ignore */
+    setOpacity = function(element, value) {
+      element.style.opacity = value;
+      return element;
+    };
+  }
+  else if (supportsFilters) {
+    /** @ignore */
+    setOpacity = function(element, value) {
+      var es = element.style;
+      if (element.currentStyle && !element.currentStyle.hasLayout) {
+        es.zoom = 1;
+      }
+      if (reOpacity.test(es.filter)) {
+        value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')');
+        es.filter = es.filter.replace(reOpacity, value);
+      }
+      else {
+        es.filter += ' alpha(opacity=' + (value * 100) + ')';
+      }
+      return element;
+    };
+  }
+
+  fabric.util.setStyle = setStyle;
+
+})();
+
+
+(function() {
+
+  var _slice = Array.prototype.slice;
+
+  /**
+   * Takes id and returns an element with that id (if one exists in a document)
+   * @memberOf fabric.util
+   * @param {String|HTMLElement} id
+   * @return {HTMLElement|null}
+   */
+  function getById(id) {
+    return typeof id === 'string' ? fabric.document.getElementById(id) : id;
+  }
+
+  var sliceCanConvertNodelists,
+      /**
+       * Converts an array-like object (e.g. arguments or NodeList) to an array
+       * @memberOf fabric.util
+       * @param {Object} arrayLike
+       * @return {Array}
+       */
+      toArray = function(arrayLike) {
+        return _slice.call(arrayLike, 0);
+      };
+
+  try {
+    sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;
+  }
+  catch (err) { }
+
+  if (!sliceCanConvertNodelists) {
+    toArray = function(arrayLike) {
+      var arr = new Array(arrayLike.length), i = arrayLike.length;
+      while (i--) {
+        arr[i] = arrayLike[i];
+      }
+      return arr;
+    };
+  }
+
+  /**
+   * Creates specified element with specified attributes
+   * @memberOf fabric.util
+   * @param {String} tagName Type of an element to create
+   * @param {Object} [attributes] Attributes to set on an element
+   * @return {HTMLElement} Newly created element
+   */
+  function makeElement(tagName, attributes) {
+    var el = fabric.document.createElement(tagName);
+    for (var prop in attributes) {
+      if (prop === 'class') {
+        el.className = attributes[prop];
+      }
+      else if (prop === 'for') {
+        el.htmlFor = attributes[prop];
+      }
+      else {
+        el.setAttribute(prop, attributes[prop]);
+      }
+    }
+    return el;
+  }
+
+  /**
+   * Adds class to an element
+   * @memberOf fabric.util
+   * @param {HTMLElement} element Element to add class to
+   * @param {String} className Class to add to an element
+   */
+  function addClass(element, className) {
+    if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {
+      element.className += (element.className ? ' ' : '') + className;
+    }
+  }
+
+  /**
+   * Wraps element with another element
+   * @memberOf fabric.util
+   * @param {HTMLElement} element Element to wrap
+   * @param {HTMLElement|String} wrapper Element to wrap with
+   * @param {Object} [attributes] Attributes to set on a wrapper
+   * @return {HTMLElement} wrapper
+   */
+  function wrapElement(element, wrapper, attributes) {
+    if (typeof wrapper === 'string') {
+      wrapper = makeElement(wrapper, attributes);
+    }
+    if (element.parentNode) {
+      element.parentNode.replaceChild(wrapper, element);
+    }
+    wrapper.appendChild(element);
+    return wrapper;
+  }
+
+  /**
+   * Returns element scroll offsets
+   * @memberOf fabric.util
+   * @param {HTMLElement} element Element to operate on
+   * @return {Object} Object with left/top values
+   */
+  function getScrollLeftTop(element) {
+
+    var left = 0,
+        top = 0,
+        docElement = fabric.document.documentElement,
+        body = fabric.document.body || {
+          scrollLeft: 0, scrollTop: 0
+        };
+
+    // While loop checks (and then sets element to) .parentNode OR .host
+    //  to account for ShadowDOM. We still want to traverse up out of ShadowDOM,
+    //  but the .parentNode of a root ShadowDOM node will always be null, instead
+    //  it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938
+    while (element && (element.parentNode || element.host)) {
+
+      // Set element to element parent, or 'host' in case of ShadowDOM
+      element = element.parentNode || element.host;
+
+      if (element === fabric.document) {
+        left = body.scrollLeft || docElement.scrollLeft || 0;
+        top = body.scrollTop ||  docElement.scrollTop || 0;
+      }
+      else {
+        left += element.scrollLeft || 0;
+        top += element.scrollTop || 0;
+      }
+
+      if (element.nodeType === 1 &&
+          fabric.util.getElementStyle(element, 'position') === 'fixed') {
+        break;
+      }
+    }
+
+    return { left: left, top: top };
+  }
+
+  /**
+   * Returns offset for a given element
+   * @function
+   * @memberOf fabric.util
+   * @param {HTMLElement} element Element to get offset for
+   * @return {Object} Object with "left" and "top" properties
+   */
+  function getElementOffset(element) {
+    var docElem,
+        doc = element && element.ownerDocument,
+        box = { left: 0, top: 0 },
+        offset = { left: 0, top: 0 },
+        scrollLeftTop,
+        offsetAttributes = {
+          borderLeftWidth: 'left',
+          borderTopWidth:  'top',
+          paddingLeft:     'left',
+          paddingTop:      'top'
+        };
+
+    if (!doc) {
+      return offset;
+    }
+
+    for (var attr in offsetAttributes) {
+      offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;
+    }
+
+    docElem = doc.documentElement;
+    if ( typeof element.getBoundingClientRect !== 'undefined' ) {
+      box = element.getBoundingClientRect();
+    }
+
+    scrollLeftTop = getScrollLeftTop(element);
+
+    return {
+      left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,
+      top: box.top + scrollLeftTop.top - (docElem.clientTop || 0)  + offset.top
+    };
+  }
+
+  /**
+   * Returns style attribute value of a given element
+   * @memberOf fabric.util
+   * @param {HTMLElement} element Element to get style attribute for
+   * @param {String} attr Style attribute to get for element
+   * @return {String} Style attribute value of the given element.
+   */
+  var getElementStyle;
+  if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {
+    getElementStyle = function(element, attr) {
+      var style = fabric.document.defaultView.getComputedStyle(element, null);
+      return style ? style[attr] : undefined;
+    };
+  }
+  else {
+    getElementStyle = function(element, attr) {
+      var value = element.style[attr];
+      if (!value && element.currentStyle) {
+        value = element.currentStyle[attr];
+      }
+      return value;
+    };
+  }
+
+  (function () {
+    var style = fabric.document.documentElement.style,
+        selectProp = 'userSelect' in style
+          ? 'userSelect'
+          : 'MozUserSelect' in style
+            ? 'MozUserSelect'
+            : 'WebkitUserSelect' in style
+              ? 'WebkitUserSelect'
+              : 'KhtmlUserSelect' in style
+                ? 'KhtmlUserSelect'
+                : '';
+
+    /**
+     * Makes element unselectable
+     * @memberOf fabric.util
+     * @param {HTMLElement} element Element to make unselectable
+     * @return {HTMLElement} Element that was passed in
+     */
+    function makeElementUnselectable(element) {
+      if (typeof element.onselectstart !== 'undefined') {
+        element.onselectstart = fabric.util.falseFunction;
+      }
+      if (selectProp) {
+        element.style[selectProp] = 'none';
+      }
+      else if (typeof element.unselectable === 'string') {
+        element.unselectable = 'on';
+      }
+      return element;
+    }
+
+    /**
+     * Makes element selectable
+     * @memberOf fabric.util
+     * @param {HTMLElement} element Element to make selectable
+     * @return {HTMLElement} Element that was passed in
+     */
+    function makeElementSelectable(element) {
+      if (typeof element.onselectstart !== 'undefined') {
+        element.onselectstart = null;
+      }
+      if (selectProp) {
+        element.style[selectProp] = '';
+      }
+      else if (typeof element.unselectable === 'string') {
+        element.unselectable = '';
+      }
+      return element;
+    }
+
+    fabric.util.makeElementUnselectable = makeElementUnselectable;
+    fabric.util.makeElementSelectable = makeElementSelectable;
+  })();
+
+  (function() {
+
+    /**
+     * Inserts a script element with a given url into a document; invokes callback, when that script is finished loading
+     * @memberOf fabric.util
+     * @param {String} url URL of a script to load
+     * @param {Function} callback Callback to execute when script is finished loading
+     */
+    function getScript(url, callback) {
+      var headEl = fabric.document.getElementsByTagName('head')[0],
+          scriptEl = fabric.document.createElement('script'),
+          loading = true;
+
+      /** @ignore */
+      scriptEl.onload = /** @ignore */ scriptEl.onreadystatechange = function(e) {
+        if (loading) {
+          if (typeof this.readyState === 'string' &&
+              this.readyState !== 'loaded' &&
+              this.readyState !== 'complete') {
+            return;
+          }
+          loading = false;
+          callback(e || fabric.window.event);
+          scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null;
+        }
+      };
+      scriptEl.src = url;
+      headEl.appendChild(scriptEl);
+      // causes issue in Opera
+      // headEl.removeChild(scriptEl);
+    }
+
+    fabric.util.getScript = getScript;
+  })();
+
+  fabric.util.getById = getById;
+  fabric.util.toArray = toArray;
+  fabric.util.makeElement = makeElement;
+  fabric.util.addClass = addClass;
+  fabric.util.wrapElement = wrapElement;
+  fabric.util.getScrollLeftTop = getScrollLeftTop;
+  fabric.util.getElementOffset = getElementOffset;
+  fabric.util.getElementStyle = getElementStyle;
+
+})();
+
+
+(function() {
+
+  function addParamToUrl(url, param) {
+    return url + (/\?/.test(url) ? '&' : '?') + param;
+  }
+
+  var makeXHR = (function() {
+    var factories = [
+      function() { return new ActiveXObject('Microsoft.XMLHTTP'); },
+      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
+      function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); },
+      function() { return new XMLHttpRequest(); }
+    ];
+    for (var i = factories.length; i--; ) {
+      try {
+        var req = factories[i]();
+        if (req) {
+          return factories[i];
+        }
+      }
+      catch (err) { }
+    }
+  })();
+
+  function emptyFn() { }
+
+  /**
+   * Cross-browser abstraction for sending XMLHttpRequest
+   * @memberOf fabric.util
+   * @param {String} url URL to send XMLHttpRequest to
+   * @param {Object} [options] Options object
+   * @param {String} [options.method="GET"]
+   * @param {String} [options.parameters] parameters to append to url in GET or in body
+   * @param {String} [options.body] body to send with POST or PUT request
+   * @param {Function} options.onComplete Callback to invoke when request is completed
+   * @return {XMLHttpRequest} request
+   */
+  function request(url, options) {
+
+    options || (options = { });
+
+    var method = options.method ? options.method.toUpperCase() : 'GET',
+        onComplete = options.onComplete || function() { },
+        xhr = makeXHR(),
+        body = options.body || options.parameters;
+
+    /** @ignore */
+    xhr.onreadystatechange = function() {
+      if (xhr.readyState === 4) {
+        onComplete(xhr);
+        xhr.onreadystatechange = emptyFn;
+      }
+    };
+
+    if (method === 'GET') {
+      body = null;
+      if (typeof options.parameters === 'string') {
+        url = addParamToUrl(url, options.parameters);
+      }
+    }
+
+    xhr.open(method, url, true);
+
+    if (method === 'POST' || method === 'PUT') {
+      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+    }
+
+    xhr.send(body);
+    return xhr;
+  }
+
+  fabric.util.request = request;
+})();
+
+
+/**
+ * Wrapper around `console.log` (when available)
+ * @param {*} [values] Values to log
+ */
+fabric.log = function() { };
+
+/**
+ * Wrapper around `console.warn` (when available)
+ * @param {*} [values] Values to log as a warning
+ */
+fabric.warn = function() { };
+
+/* eslint-disable */
+if (typeof console !== 'undefined') {
+
+  ['log', 'warn'].forEach(function(methodName) {
+
+    if (typeof console[methodName] !== 'undefined' &&
+        typeof console[methodName].apply === 'function') {
+
+      fabric[methodName] = function() {
+        return console[methodName].apply(console, arguments);
+      };
+    }
+  });
+}
+/* eslint-enable */
+
+
+(function() {
+
+  /**
+   * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.
+   * @memberOf fabric.util
+   * @param {Object} [options] Animation options
+   * @param {Function} [options.onChange] Callback; invoked on every value change
+   * @param {Function} [options.onComplete] Callback; invoked when value change is completed
+   * @param {Number} [options.startValue=0] Starting value
+   * @param {Number} [options.endValue=100] Ending value
+   * @param {Number} [options.byValue=100] Value to modify the property by
+   * @param {Function} [options.easing] Easing function
+   * @param {Number} [options.duration=500] Duration of change (in ms)
+   */
+  function animate(options) {
+
+    requestAnimFrame(function(timestamp) {
+      options || (options = { });
+
+      var start = timestamp || +new Date(),
+          duration = options.duration || 500,
+          finish = start + duration, time,
+          onChange = options.onChange || function() { },
+          abort = options.abort || function() { return false; },
+          easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;},
+          startValue = 'startValue' in options ? options.startValue : 0,
+          endValue = 'endValue' in options ? options.endValue : 100,
+          byValue = options.byValue || endValue - startValue;
+
+      options.onStart && options.onStart();
+
+      (function tick(ticktime) {
+        time = ticktime || +new Date();
+        var currentTime = time > finish ? duration : (time - start);
+        if (abort()) {
+          options.onComplete && options.onComplete();
+          return;
+        }
+        onChange(easing(currentTime, startValue, byValue, duration));
+        if (time > finish) {
+          options.onComplete && options.onComplete();
+          return;
+        }
+        requestAnimFrame(tick);
+      })(start);
+    });
+
+  }
+
+  var _requestAnimFrame = fabric.window.requestAnimationFrame       ||
+                          fabric.window.webkitRequestAnimationFrame ||
+                          fabric.window.mozRequestAnimationFrame    ||
+                          fabric.window.oRequestAnimationFrame      ||
+                          fabric.window.msRequestAnimationFrame     ||
+                          function(callback) {
+                            fabric.window.setTimeout(callback, 1000 / 60);
+                          };
+
+  /**
+   * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+   * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method
+   * @memberOf fabric.util
+   * @param {Function} callback Callback to invoke
+   * @param {DOMElement} element optional Element to associate with animation
+   */
+  function requestAnimFrame() {
+    return _requestAnimFrame.apply(fabric.window, arguments);
+  }
+
+  fabric.util.animate = animate;
+  fabric.util.requestAnimFrame = requestAnimFrame;
+
+})();
+
+
+(function() {
+
+  function normalize(a, c, p, s) {
+    if (a < Math.abs(c)) {
+      a = c;
+      s = p / 4;
+    }
+    else {
+      //handle the 0/0 case:
+      if (c === 0 && a === 0) {
+        s = p / (2 * Math.PI) * Math.asin(1);
+      }
+      else {
+        s = p / (2 * Math.PI) * Math.asin(c / a);
+      }
+    }
+    return { a: a, c: c, p: p, s: s };
+  }
+
+  function elastic(opts, t, d) {
+    return opts.a *
+      Math.pow(2, 10 * (t -= 1)) *
+      Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p );
+  }
+
+  /**
+   * Cubic easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutCubic(t, b, c, d) {
+    return c * ((t = t / d - 1) * t * t + 1) + b;
+  }
+
+  /**
+   * Cubic easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutCubic(t, b, c, d) {
+    t /= d / 2;
+    if (t < 1) {
+      return c / 2 * t * t * t + b;
+    }
+    return c / 2 * ((t -= 2) * t * t + 2) + b;
+  }
+
+  /**
+   * Quartic easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInQuart(t, b, c, d) {
+    return c * (t /= d) * t * t * t + b;
+  }
+
+  /**
+   * Quartic easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutQuart(t, b, c, d) {
+    return -c * ((t = t / d - 1) * t * t * t - 1) + b;
+  }
+
+  /**
+   * Quartic easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutQuart(t, b, c, d) {
+    t /= d / 2;
+    if (t < 1) {
+      return c / 2 * t * t * t * t + b;
+    }
+    return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
+  }
+
+  /**
+   * Quintic easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInQuint(t, b, c, d) {
+    return c * (t /= d) * t * t * t * t + b;
+  }
+
+  /**
+   * Quintic easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutQuint(t, b, c, d) {
+    return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
+  }
+
+  /**
+   * Quintic easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutQuint(t, b, c, d) {
+    t /= d / 2;
+    if (t < 1) {
+      return c / 2 * t * t * t * t * t + b;
+    }
+    return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
+  }
+
+  /**
+   * Sinusoidal easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInSine(t, b, c, d) {
+    return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
+  }
+
+  /**
+   * Sinusoidal easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutSine(t, b, c, d) {
+    return c * Math.sin(t / d * (Math.PI / 2)) + b;
+  }
+
+  /**
+   * Sinusoidal easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutSine(t, b, c, d) {
+    return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
+  }
+
+  /**
+   * Exponential easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInExpo(t, b, c, d) {
+    return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
+  }
+
+  /**
+   * Exponential easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutExpo(t, b, c, d) {
+    return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
+  }
+
+  /**
+   * Exponential easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutExpo(t, b, c, d) {
+    if (t === 0) {
+      return b;
+    }
+    if (t === d) {
+      return b + c;
+    }
+    t /= d / 2;
+    if (t < 1) {
+      return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
+    }
+    return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
+  }
+
+  /**
+   * Circular easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInCirc(t, b, c, d) {
+    return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
+  }
+
+  /**
+   * Circular easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutCirc(t, b, c, d) {
+    return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
+  }
+
+  /**
+   * Circular easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutCirc(t, b, c, d) {
+    t /= d / 2;
+    if (t < 1) {
+      return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
+    }
+    return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
+  }
+
+  /**
+   * Elastic easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInElastic(t, b, c, d) {
+    var s = 1.70158, p = 0, a = c;
+    if (t === 0) {
+      return b;
+    }
+    t /= d;
+    if (t === 1) {
+      return b + c;
+    }
+    if (!p) {
+      p = d * 0.3;
+    }
+    var opts = normalize(a, c, p, s);
+    return -elastic(opts, t, d) + b;
+  }
+
+  /**
+   * Elastic easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutElastic(t, b, c, d) {
+    var s = 1.70158, p = 0, a = c;
+    if (t === 0) {
+      return b;
+    }
+    t /= d;
+    if (t === 1) {
+      return b + c;
+    }
+    if (!p) {
+      p = d * 0.3;
+    }
+    var opts = normalize(a, c, p, s);
+    return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b;
+  }
+
+  /**
+   * Elastic easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutElastic(t, b, c, d) {
+    var s = 1.70158, p = 0, a = c;
+    if (t === 0) {
+      return b;
+    }
+    t /= d / 2;
+    if (t === 2) {
+      return b + c;
+    }
+    if (!p) {
+      p = d * (0.3 * 1.5);
+    }
+    var opts = normalize(a, c, p, s);
+    if (t < 1) {
+      return -0.5 * elastic(opts, t, d) + b;
+    }
+    return opts.a * Math.pow(2, -10 * (t -= 1)) *
+      Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b;
+  }
+
+  /**
+   * Backwards easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInBack(t, b, c, d, s) {
+    if (s === undefined) {
+      s = 1.70158;
+    }
+    return c * (t /= d) * t * ((s + 1) * t - s) + b;
+  }
+
+  /**
+   * Backwards easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutBack(t, b, c, d, s) {
+    if (s === undefined) {
+      s = 1.70158;
+    }
+    return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
+  }
+
+  /**
+   * Backwards easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutBack(t, b, c, d, s) {
+    if (s === undefined) {
+      s = 1.70158;
+    }
+    t /= d / 2;
+    if (t < 1) {
+      return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
+    }
+    return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
+  }
+
+  /**
+   * Bouncing easing in
+   * @memberOf fabric.util.ease
+   */
+  function easeInBounce(t, b, c, d) {
+    return c - easeOutBounce (d - t, 0, c, d) + b;
+  }
+
+  /**
+   * Bouncing easing out
+   * @memberOf fabric.util.ease
+   */
+  function easeOutBounce(t, b, c, d) {
+    if ((t /= d) < (1 / 2.75)) {
+      return c * (7.5625 * t * t) + b;
+    }
+    else if (t < (2 / 2.75)) {
+      return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
+    }
+    else if (t < (2.5 / 2.75)) {
+      return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
+    }
+    else {
+      return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
+    }
+  }
+
+  /**
+   * Bouncing easing in and out
+   * @memberOf fabric.util.ease
+   */
+  function easeInOutBounce(t, b, c, d) {
+    if (t < d / 2) {
+      return easeInBounce (t * 2, 0, c, d) * 0.5 + b;
+    }
+    return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
+  }
+
+  /**
+   * Easing functions
+   * See <a href="http://gizma.com/easing/">Easing Equations by Robert Penner</a>
+   * @namespace fabric.util.ease
+   */
+  fabric.util.ease = {
+
+    /**
+     * Quadratic easing in
+     * @memberOf fabric.util.ease
+     */
+    easeInQuad: function(t, b, c, d) {
+      return c * (t /= d) * t + b;
+    },
+
+    /**
+     * Quadratic easing out
+     * @memberOf fabric.util.ease
+     */
+    easeOutQuad: function(t, b, c, d) {
+      return -c * (t /= d) * (t - 2) + b;
+    },
+
+    /**
+     * Quadratic easing in and out
+     * @memberOf fabric.util.ease
+     */
+    easeInOutQuad: function(t, b, c, d) {
+      t /= (d / 2);
+      if (t < 1) {
+        return c / 2 * t * t + b;
+      }
+      return -c / 2 * ((--t) * (t - 2) - 1) + b;
+    },
+
+    /**
+     * Cubic easing in
+     * @memberOf fabric.util.ease
+     */
+    easeInCubic: function(t, b, c, d) {
+      return c * (t /= d) * t * t + b;
+    },
+
+    easeOutCubic: easeOutCubic,
+    easeInOutCubic: easeInOutCubic,
+    easeInQuart: easeInQuart,
+    easeOutQuart: easeOutQuart,
+    easeInOutQuart: easeInOutQuart,
+    easeInQuint: easeInQuint,
+    easeOutQuint: easeOutQuint,
+    easeInOutQuint: easeInOutQuint,
+    easeInSine: easeInSine,
+    easeOutSine: easeOutSine,
+    easeInOutSine: easeInOutSine,
+    easeInExpo: easeInExpo,
+    easeOutExpo: easeOutExpo,
+    easeInOutExpo: easeInOutExpo,
+    easeInCirc: easeInCirc,
+    easeOutCirc: easeOutCirc,
+    easeInOutCirc: easeInOutCirc,
+    easeInElastic: easeInElastic,
+    easeOutElastic: easeOutElastic,
+    easeInOutElastic: easeInOutElastic,
+    easeInBack: easeInBack,
+    easeOutBack: easeOutBack,
+    easeInOutBack: easeInOutBack,
+    easeInBounce: easeInBounce,
+    easeOutBounce: easeOutBounce,
+    easeInOutBounce: easeInOutBounce
+  };
+
+})();
+
+
+(function(global) {
+
+  'use strict';
+
+  /**
+   * @name fabric
+   * @namespace
+   */
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      capitalize = fabric.util.string.capitalize,
+      clone = fabric.util.object.clone,
+      toFixed = fabric.util.toFixed,
+      parseUnit = fabric.util.parseUnit,
+      multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,
+
+      reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,
+      reViewBoxTagNames = /^(symbol|image|marker|pattern|view|svg)$/i,
+      reNotAllowedAncestors = /^(?:pattern|defs|symbol|metadata)$/i,
+      reAllowedParents = /^(symbol|g|a|svg)$/i,
+
+      attributesMap = {
+        cx:                   'left',
+        x:                    'left',
+        r:                    'radius',
+        cy:                   'top',
+        y:                    'top',
+        display:              'visible',
+        visibility:           'visible',
+        transform:            'transformMatrix',
+        'fill-opacity':       'fillOpacity',
+        'fill-rule':          'fillRule',
+        'font-family':        'fontFamily',
+        'font-size':          'fontSize',
+        'font-style':         'fontStyle',
+        'font-weight':        'fontWeight',
+        'stroke-dasharray':   'strokeDashArray',
+        'stroke-linecap':     'strokeLineCap',
+        'stroke-linejoin':    'strokeLineJoin',
+        'stroke-miterlimit':  'strokeMiterLimit',
+        'stroke-opacity':     'strokeOpacity',
+        'stroke-width':       'strokeWidth',
+        'text-decoration':    'textDecoration',
+        'text-anchor':        'originX'
+      },
+
+      colorAttributes = {
+        stroke: 'strokeOpacity',
+        fill:   'fillOpacity'
+      };
+
+  fabric.cssRules = { };
+  fabric.gradientDefs = { };
+
+  function normalizeAttr(attr) {
+    // transform attribute names
+    if (attr in attributesMap) {
+      return attributesMap[attr];
+    }
+    return attr;
+  }
+
+  function normalizeValue(attr, value, parentAttributes, fontSize) {
+    var isArray = Object.prototype.toString.call(value) === '[object Array]',
+        parsed;
+
+    if ((attr === 'fill' || attr === 'stroke') && value === 'none') {
+      value = '';
+    }
+    else if (attr === 'strokeDashArray') {
+      value = value.replace(/,/g, ' ').split(/\s+/).map(function(n) {
+        return parseFloat(n);
+      });
+    }
+    else if (attr === 'transformMatrix') {
+      if (parentAttributes && parentAttributes.transformMatrix) {
+        value = multiplyTransformMatrices(
+          parentAttributes.transformMatrix, fabric.parseTransformAttribute(value));
+      }
+      else {
+        value = fabric.parseTransformAttribute(value);
+      }
+    }
+    else if (attr === 'visible') {
+      value = (value === 'none' || value === 'hidden') ? false : true;
+      // display=none on parent element always takes precedence over child element
+      if (parentAttributes && parentAttributes.visible === false) {
+        value = false;
+      }
+    }
+    else if (attr === 'originX' /* text-anchor */) {
+      value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';
+    }
+    else {
+      parsed = isArray ? value.map(parseUnit) : parseUnit(value, fontSize);
+    }
+
+    return (!isArray && isNaN(parsed) ? value : parsed);
+  }
+
+  /**
+   * @private
+   * @param {Object} attributes Array of attributes to parse
+   */
+  function _setStrokeFillOpacity(attributes) {
+    for (var attr in colorAttributes) {
+
+      if (typeof attributes[colorAttributes[attr]] === 'undefined' || attributes[attr] === '') {
+        continue;
+      }
+
+      if (typeof attributes[attr] === 'undefined') {
+        if (!fabric.Object.prototype[attr]) {
+          continue;
+        }
+        attributes[attr] = fabric.Object.prototype[attr];
+      }
+
+      if (attributes[attr].indexOf('url(') === 0) {
+        continue;
+      }
+
+      var color = new fabric.Color(attributes[attr]);
+      attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();
+    }
+    return attributes;
+  }
+
+  /**
+   * @private
+   */
+  function _getMultipleNodes(doc, nodeNames) {
+    var nodeName, nodeArray = [], nodeList;
+    for (var i = 0; i < nodeNames.length; i++) {
+      nodeName = nodeNames[i];
+      nodeList = doc.getElementsByTagName(nodeName);
+      nodeArray = nodeArray.concat(Array.prototype.slice.call(nodeList));
+    }
+    return nodeArray;
+  }
+
+  /**
+   * Parses "transform" attribute, returning an array of values
+   * @static
+   * @function
+   * @memberOf fabric
+   * @param {String} attributeValue String containing attribute value
+   * @return {Array} Array of 6 elements representing transformation matrix
+   */
+  fabric.parseTransformAttribute = (function() {
+    function rotateMatrix(matrix, args) {
+      var angle = args[0],
+          x = (args.length === 3) ? args[1] : 0,
+          y = (args.length === 3) ? args[2] : 0;
+
+      matrix[0] = Math.cos(angle);
+      matrix[1] = Math.sin(angle);
+      matrix[2] = -Math.sin(angle);
+      matrix[3] = Math.cos(angle);
+      matrix[4] = x - (matrix[0] * x + matrix[2] * y);
+      matrix[5] = y - (matrix[1] * x + matrix[3] * y);
+    }
+
+    function scaleMatrix(matrix, args) {
+      var multiplierX = args[0],
+          multiplierY = (args.length === 2) ? args[1] : args[0];
+
+      matrix[0] = multiplierX;
+      matrix[3] = multiplierY;
+    }
+
+    function skewXMatrix(matrix, args) {
+      matrix[2] = Math.tan(fabric.util.degreesToRadians(args[0]));
+    }
+
+    function skewYMatrix(matrix, args) {
+      matrix[1] = Math.tan(fabric.util.degreesToRadians(args[0]));
+    }
+
+    function translateMatrix(matrix, args) {
+      matrix[4] = args[0];
+      if (args.length === 2) {
+        matrix[5] = args[1];
+      }
+    }
+
+    // identity matrix
+    var iMatrix = [
+          1, // a
+          0, // b
+          0, // c
+          1, // d
+          0, // e
+          0  // f
+        ],
+
+        // == begin transform regexp
+        number = fabric.reNum,
+
+        commaWsp = '(?:\\s+,?\\s*|,\\s*)',
+
+        skewX = '(?:(skewX)\\s*\\(\\s*(' + number + ')\\s*\\))',
+
+        skewY = '(?:(skewY)\\s*\\(\\s*(' + number + ')\\s*\\))',
+
+        rotate = '(?:(rotate)\\s*\\(\\s*(' + number + ')(?:' +
+                    commaWsp + '(' + number + ')' +
+                    commaWsp + '(' + number + '))?\\s*\\))',
+
+        scale = '(?:(scale)\\s*\\(\\s*(' + number + ')(?:' +
+                    commaWsp + '(' + number + '))?\\s*\\))',
+
+        translate = '(?:(translate)\\s*\\(\\s*(' + number + ')(?:' +
+                    commaWsp + '(' + number + '))?\\s*\\))',
+
+        matrix = '(?:(matrix)\\s*\\(\\s*' +
+                  '(' + number + ')' + commaWsp +
+                  '(' + number + ')' + commaWsp +
+                  '(' + number + ')' + commaWsp +
+                  '(' + number + ')' + commaWsp +
+                  '(' + number + ')' + commaWsp +
+                  '(' + number + ')' +
+                  '\\s*\\))',
+
+        transform = '(?:' +
+                    matrix + '|' +
+                    translate + '|' +
+                    scale + '|' +
+                    rotate + '|' +
+                    skewX + '|' +
+                    skewY +
+                    ')',
+
+        transforms = '(?:' + transform + '(?:' + commaWsp + '*' + transform + ')*' + ')',
+
+        transformList = '^\\s*(?:' + transforms + '?)\\s*$',
+
+        // http://www.w3.org/TR/SVG/coords.html#TransformAttribute
+        reTransformList = new RegExp(transformList),
+        // == end transform regexp
+
+        reTransform = new RegExp(transform, 'g');
+
+    return function(attributeValue) {
+
+      // start with identity matrix
+      var matrix = iMatrix.concat(),
+          matrices = [];
+
+      // return if no argument was given or
+      // an argument does not match transform attribute regexp
+      if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) {
+        return matrix;
+      }
+
+      attributeValue.replace(reTransform, function(match) {
+
+        var m = new RegExp(transform).exec(match).filter(function (match) {
+              // match !== '' && match != null
+              return (!!match);
+            }),
+            operation = m[1],
+            args = m.slice(2).map(parseFloat);
+
+        switch (operation) {
+          case 'translate':
+            translateMatrix(matrix, args);
+            break;
+          case 'rotate':
+            args[0] = fabric.util.degreesToRadians(args[0]);
+            rotateMatrix(matrix, args);
+            break;
+          case 'scale':
+            scaleMatrix(matrix, args);
+            break;
+          case 'skewX':
+            skewXMatrix(matrix, args);
+            break;
+          case 'skewY':
+            skewYMatrix(matrix, args);
+            break;
+          case 'matrix':
+            matrix = args;
+            break;
+        }
+
+        // snapshot current matrix into matrices array
+        matrices.push(matrix.concat());
+        // reset
+        matrix = iMatrix.concat();
+      });
+
+      var combinedMatrix = matrices[0];
+      while (matrices.length > 1) {
+        matrices.shift();
+        combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]);
+      }
+      return combinedMatrix;
+    };
+  })();
+
+  /**
+   * @private
+   */
+  function parseStyleString(style, oStyle) {
+    var attr, value;
+    style.replace(/;\s*$/, '').split(';').forEach(function (chunk) {
+      var pair = chunk.split(':');
+
+      attr = normalizeAttr(pair[0].trim().toLowerCase());
+      value = normalizeValue(attr, pair[1].trim());
+
+      oStyle[attr] = value;
+    });
+  }
+
+  /**
+   * @private
+   */
+  function parseStyleObject(style, oStyle) {
+    var attr, value;
+    for (var prop in style) {
+      if (typeof style[prop] === 'undefined') {
+        continue;
+      }
+
+      attr = normalizeAttr(prop.toLowerCase());
+      value = normalizeValue(attr, style[prop]);
+
+      oStyle[attr] = value;
+    }
+  }
+
+  /**
+   * @private
+   */
+  function getGlobalStylesForElement(element, svgUid) {
+    var styles = { };
+    for (var rule in fabric.cssRules[svgUid]) {
+      if (elementMatchesRule(element, rule.split(' '))) {
+        for (var property in fabric.cssRules[svgUid][rule]) {
+          styles[property] = fabric.cssRules[svgUid][rule][property];
+        }
+      }
+    }
+    return styles;
+  }
+
+  /**
+   * @private
+   */
+  function elementMatchesRule(element, selectors) {
+    var firstMatching, parentMatching = true;
+    //start from rightmost selector.
+    firstMatching = selectorMatches(element, selectors.pop());
+    if (firstMatching && selectors.length) {
+      parentMatching = doesSomeParentMatch(element, selectors);
+    }
+    return firstMatching && parentMatching && (selectors.length === 0);
+  }
+
+  function doesSomeParentMatch(element, selectors) {
+    var selector, parentMatching = true;
+    while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) {
+      if (parentMatching) {
+        selector = selectors.pop();
+      }
+      element = element.parentNode;
+      parentMatching = selectorMatches(element, selector);
+    }
+    return selectors.length === 0;
+  }
+
+  /**
+   * @private
+   */
+  function selectorMatches(element, selector) {
+    var nodeName = element.nodeName,
+        classNames = element.getAttribute('class'),
+        id = element.getAttribute('id'), matcher;
+    // i check if a selector matches slicing away part from it.
+    // if i get empty string i should match
+    matcher = new RegExp('^' + nodeName, 'i');
+    selector = selector.replace(matcher, '');
+    if (id && selector.length) {
+      matcher = new RegExp('#' + id + '(?![a-zA-Z\\-]+)', 'i');
+      selector = selector.replace(matcher, '');
+    }
+    if (classNames && selector.length) {
+      classNames = classNames.split(' ');
+      for (var i = classNames.length; i--;) {
+        matcher = new RegExp('\\.' + classNames[i] + '(?![a-zA-Z\\-]+)', 'i');
+        selector = selector.replace(matcher, '');
+      }
+    }
+    return selector.length === 0;
+  }
+
+  /**
+   * @private
+   * to support IE8 missing getElementById on SVGdocument
+   */
+  function elementById(doc, id) {
+    var el;
+    doc.getElementById && (el = doc.getElementById(id));
+    if (el) {
+      return el;
+    }
+    var node, i, nodelist = doc.getElementsByTagName('*');
+    for (i = 0; i < nodelist.length; i++) {
+      node = nodelist[i];
+      if (id === node.getAttribute('id')) {
+        return node;
+      }
+    }
+  }
+
+  /**
+   * @private
+   */
+  function parseUseDirectives(doc) {
+    var nodelist = _getMultipleNodes(doc, ['use', 'svg:use']), i = 0;
+
+    while (nodelist.length && i < nodelist.length) {
+      var el = nodelist[i],
+          xlink = el.getAttribute('xlink:href').substr(1),
+          x = el.getAttribute('x') || 0,
+          y = el.getAttribute('y') || 0,
+          el2 = elementById(doc, xlink).cloneNode(true),
+          currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',
+          parentNode, oldLength = nodelist.length, attr, j, attrs, l;
+
+      applyViewboxTransform(el2);
+      if (/^svg$/i.test(el2.nodeName)) {
+        var el3 = el2.ownerDocument.createElement('g');
+        for (j = 0, attrs = el2.attributes, l = attrs.length; j < l; j++) {
+          attr = attrs.item(j);
+          el3.setAttribute(attr.nodeName, attr.nodeValue);
+        }
+        // el2.firstChild != null
+        while (el2.firstChild) {
+          el3.appendChild(el2.firstChild);
+        }
+        el2 = el3;
+      }
+
+      for (j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) {
+        attr = attrs.item(j);
+        if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') {
+          continue;
+        }
+
+        if (attr.nodeName === 'transform') {
+          currentTrans = attr.nodeValue + ' ' + currentTrans;
+        }
+        else {
+          el2.setAttribute(attr.nodeName, attr.nodeValue);
+        }
+      }
+
+      el2.setAttribute('transform', currentTrans);
+      el2.setAttribute('instantiated_by_use', '1');
+      el2.removeAttribute('id');
+      parentNode = el.parentNode;
+      parentNode.replaceChild(el2, el);
+      // some browsers do not shorten nodelist after replaceChild (IE8)
+      if (nodelist.length === oldLength) {
+        i++;
+      }
+    }
+  }
+
+  // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
+  // matches, e.g.: +14.56e-12, etc.
+  var reViewBoxAttrValue = new RegExp(
+    '^' +
+    '\\s*(' + fabric.reNum + '+)\\s*,?' +
+    '\\s*(' + fabric.reNum + '+)\\s*,?' +
+    '\\s*(' + fabric.reNum + '+)\\s*,?' +
+    '\\s*(' + fabric.reNum + '+)\\s*' +
+    '$'
+  );
+
+  /**
+   * Add a <g> element that envelop all child elements and makes the viewbox transformMatrix descend on all elements
+   */
+  function applyViewboxTransform(element) {
+
+    var viewBoxAttr = element.getAttribute('viewBox'),
+        scaleX = 1,
+        scaleY = 1,
+        minX = 0,
+        minY = 0,
+        viewBoxWidth, viewBoxHeight, matrix, el,
+        widthAttr = element.getAttribute('width'),
+        heightAttr = element.getAttribute('height'),
+        x = element.getAttribute('x') || 0,
+        y = element.getAttribute('y') || 0,
+        preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '',
+        missingViewBox = (!viewBoxAttr || !reViewBoxTagNames.test(element.nodeName)
+                           || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))),
+        missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'),
+        toBeParsed = missingViewBox && missingDimAttr,
+        parsedDim = { }, translateMatrix = '';
+
+    parsedDim.width = 0;
+    parsedDim.height = 0;
+    parsedDim.toBeParsed = toBeParsed;
+
+    if (toBeParsed) {
+      return parsedDim;
+    }
+
+    if (missingViewBox) {
+      parsedDim.width = parseUnit(widthAttr);
+      parsedDim.height = parseUnit(heightAttr);
+      return parsedDim;
+    }
+
+    minX = -parseFloat(viewBoxAttr[1]);
+    minY = -parseFloat(viewBoxAttr[2]);
+    viewBoxWidth = parseFloat(viewBoxAttr[3]);
+    viewBoxHeight = parseFloat(viewBoxAttr[4]);
+
+    if (!missingDimAttr) {
+      parsedDim.width = parseUnit(widthAttr);
+      parsedDim.height = parseUnit(heightAttr);
+      scaleX = parsedDim.width / viewBoxWidth;
+      scaleY = parsedDim.height / viewBoxHeight;
+    }
+    else {
+      parsedDim.width = viewBoxWidth;
+      parsedDim.height = viewBoxHeight;
+    }
+
+    // default is to preserve aspect ratio
+    preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio);
+    if (preserveAspectRatio.alignX !== 'none') {
+      //translate all container for the effect of Mid, Min, Max
+      scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX);
+    }
+
+    if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) {
+      return parsedDim;
+    }
+
+    if (x || y) {
+      translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';
+    }
+
+    matrix = translateMatrix + ' matrix(' + scaleX +
+                  ' 0' +
+                  ' 0 ' +
+                  scaleY + ' ' +
+                  (minX * scaleX) + ' ' +
+                  (minY * scaleY) + ') ';
+
+    if (element.nodeName === 'svg') {
+      el = element.ownerDocument.createElement('g');
+      // element.firstChild != null
+      while (element.firstChild) {
+        el.appendChild(element.firstChild);
+      }
+      element.appendChild(el);
+    }
+    else {
+      el = element;
+      matrix = el.getAttribute('transform') + matrix;
+    }
+
+    el.setAttribute('transform', matrix);
+    return parsedDim;
+  }
+
+  /**
+   * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback
+   * @static
+   * @function
+   * @memberOf fabric
+   * @param {SVGDocument} doc SVG document to parse
+   * @param {Function} callback Callback to call when parsing is finished;
+   * It's being passed an array of elements (parsed from a document).
+   * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.
+   */
+  fabric.parseSVGDocument = (function() {
+
+    function hasAncestorWithNodeName(element, nodeName) {
+      while (element && (element = element.parentNode)) {
+        if (element.nodeName && nodeName.test(element.nodeName.replace('svg:', ''))
+          && !element.getAttribute('instantiated_by_use')) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    return function(doc, callback, reviver) {
+      if (!doc) {
+        return;
+      }
+
+      parseUseDirectives(doc);
+
+      var startTime = new Date(),
+          svgUid =  fabric.Object.__uid++,
+          options = applyViewboxTransform(doc),
+          descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
+
+      options.svgUid = svgUid;
+
+      if (descendants.length === 0 && fabric.isLikelyNode) {
+        // we're likely in node, where "o3-xml" library fails to gEBTN("*")
+        // https://github.com/ajaxorg/node-o3-xml/issues/21
+        descendants = doc.selectNodes('//*[name(.)!="svg"]');
+        var arr = [];
+        for (var i = 0, len = descendants.length; i < len; i++) {
+          arr[i] = descendants[i];
+        }
+        descendants = arr;
+      }
+
+      var elements = descendants.filter(function(el) {
+        applyViewboxTransform(el);
+        return reAllowedSVGTagNames.test(el.nodeName.replace('svg:', '')) &&
+              !hasAncestorWithNodeName(el, reNotAllowedAncestors); // http://www.w3.org/TR/SVG/struct.html#DefsElement
+      });
+
+      if (!elements || (elements && !elements.length)) {
+        callback && callback([], {});
+        return;
+      }
+
+      fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);
+      fabric.cssRules[svgUid] = fabric.getCSSRules(doc);
+      // Precedence of rules:   style > class > attribute
+      fabric.parseElements(elements, function(instances) {
+        fabric.documentParsingTime = new Date() - startTime;
+        if (callback) {
+          callback(instances, options);
+        }
+      }, clone(options), reviver);
+    };
+  })();
+
+  /**
+   * Used for caching SVG documents (loaded via `fabric.Canvas#loadSVGFromURL`)
+   * @namespace
+   */
+  var svgCache = {
+
+    /**
+     * @param {String} name
+     * @param {Function} callback
+     */
+    has: function (name, callback) {
+      callback(false);
+    },
+
+    get: function () {
+      /* NOOP */
+    },
+
+    set: function () {
+      /* NOOP */
+    }
+  };
+
+  /**
+   * @private
+   */
+  function _enlivenCachedObject(cachedObject) {
+
+    var objects = cachedObject.objects,
+        options = cachedObject.options;
+
+    objects = objects.map(function (o) {
+      return fabric[capitalize(o.type)].fromObject(o);
+    });
+
+    return ({ objects: objects, options: options });
+  }
+
+  /**
+   * @private
+   */
+  function _createSVGPattern(markup, canvas, property) {
+    if (canvas[property] && canvas[property].toSVG) {
+      markup.push(
+        '\t<pattern x="0" y="0" id="', property, 'Pattern" ',
+          'width="', canvas[property].source.width,
+          '" height="', canvas[property].source.height,
+          '" patternUnits="userSpaceOnUse">\n',
+        '\t\t<image x="0" y="0" ',
+        'width="', canvas[property].source.width,
+        '" height="', canvas[property].source.height,
+        '" xlink:href="', canvas[property].source.src,
+        '"></image>\n\t</pattern>\n'
+      );
+    }
+  }
+
+  var reFontDeclaration = new RegExp(
+    '(normal|italic)?\\s*(normal|small-caps)?\\s*' +
+    '(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(' +
+      fabric.reNum +
+    '(?:px|cm|mm|em|pt|pc|in)*)(?:\\/(normal|' + fabric.reNum + '))?\\s+(.*)');
+
+  extend(fabric, {
+    /**
+     * Parses a short font declaration, building adding its properties to a style object
+     * @static
+     * @function
+     * @memberOf fabric
+     * @param {String} value font declaration
+     * @param {Object} oStyle definition
+     */
+    parseFontDeclaration: function(value, oStyle) {
+      var match = value.match(reFontDeclaration);
+
+      if (!match) {
+        return;
+      }
+      var fontStyle = match[1],
+          // font variant is not used
+          // fontVariant = match[2],
+          fontWeight = match[3],
+          fontSize = match[4],
+          lineHeight = match[5],
+          fontFamily = match[6];
+
+      if (fontStyle) {
+        oStyle.fontStyle = fontStyle;
+      }
+      if (fontWeight) {
+        oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);
+      }
+      if (fontSize) {
+        oStyle.fontSize = parseUnit(fontSize);
+      }
+      if (fontFamily) {
+        oStyle.fontFamily = fontFamily;
+      }
+      if (lineHeight) {
+        oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight;
+      }
+    },
+
+    /**
+     * Parses an SVG document, returning all of the gradient declarations found in it
+     * @static
+     * @function
+     * @memberOf fabric
+     * @param {SVGDocument} doc SVG document to parse
+     * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element
+     */
+    getGradientDefs: function(doc) {
+      var tagArray = [
+            'linearGradient',
+            'radialGradient',
+            'svg:linearGradient',
+            'svg:radialGradient'],
+          elList = _getMultipleNodes(doc, tagArray),
+          el, j = 0, id, xlink,
+          gradientDefs = { }, idsToXlinkMap = { };
+
+      j = elList.length;
+
+      while (j--) {
+        el = elList[j];
+        xlink = el.getAttribute('xlink:href');
+        id = el.getAttribute('id');
+        if (xlink) {
+          idsToXlinkMap[id] = xlink.substr(1);
+        }
+        gradientDefs[id] = el;
+      }
+
+      for (id in idsToXlinkMap) {
+        var el2 = gradientDefs[idsToXlinkMap[id]].cloneNode(true);
+        el = gradientDefs[id];
+        while (el2.firstChild) {
+          el.appendChild(el2.firstChild);
+        }
+      }
+      return gradientDefs;
+    },
+
+    /**
+     * Returns an object of attributes' name/value, given element and an array of attribute names;
+     * Parses parent "g" nodes recursively upwards.
+     * @static
+     * @memberOf fabric
+     * @param {DOMElement} element Element to parse
+     * @param {Array} attributes Array of attributes to parse
+     * @return {Object} object containing parsed attributes' names/values
+     */
+    parseAttributes: function(element, attributes, svgUid) {
+
+      if (!element) {
+        return;
+      }
+
+      var value,
+          parentAttributes = { },
+          fontSize;
+
+      if (typeof svgUid === 'undefined') {
+        svgUid = element.getAttribute('svgUid');
+      }
+      // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards
+      if (element.parentNode && reAllowedParents.test(element.parentNode.nodeName)) {
+        parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid);
+      }
+      fontSize = (parentAttributes && parentAttributes.fontSize ) ||
+                 element.getAttribute('font-size') || fabric.Text.DEFAULT_SVG_FONT_SIZE;
+
+      var ownAttributes = attributes.reduce(function(memo, attr) {
+        value = element.getAttribute(attr);
+        if (value) {
+          attr = normalizeAttr(attr);
+          value = normalizeValue(attr, value, parentAttributes, fontSize);
+
+          memo[attr] = value;
+        }
+        return memo;
+      }, { });
+
+      // add values parsed from style, which take precedence over attributes
+      // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)
+      ownAttributes = extend(ownAttributes,
+        extend(getGlobalStylesForElement(element, svgUid), fabric.parseStyleAttribute(element)));
+      if (ownAttributes.font) {
+        fabric.parseFontDeclaration(ownAttributes.font, ownAttributes);
+      }
+      return _setStrokeFillOpacity(extend(parentAttributes, ownAttributes));
+    },
+
+    /**
+     * Transforms an array of svg elements to corresponding fabric.* instances
+     * @static
+     * @memberOf fabric
+     * @param {Array} elements Array of elements to parse
+     * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)
+     * @param {Object} [options] Options object
+     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.
+     */
+    parseElements: function(elements, callback, options, reviver) {
+      new fabric.ElementsParser(elements, callback, options, reviver).parse();
+    },
+
+    /**
+     * Parses "style" attribute, retuning an object with values
+     * @static
+     * @memberOf fabric
+     * @param {SVGElement} element Element to parse
+     * @return {Object} Objects with values parsed from style attribute of an element
+     */
+    parseStyleAttribute: function(element) {
+      var oStyle = { },
+          style = element.getAttribute('style');
+
+      if (!style) {
+        return oStyle;
+      }
+
+      if (typeof style === 'string') {
+        parseStyleString(style, oStyle);
+      }
+      else {
+        parseStyleObject(style, oStyle);
+      }
+
+      return oStyle;
+    },
+
+    /**
+     * Parses "points" attribute, returning an array of values
+     * @static
+     * @memberOf fabric
+     * @param {String} points points attribute string
+     * @return {Array} array of points
+     */
+    parsePointsAttribute: function(points) {
+
+      // points attribute is required and must not be empty
+      if (!points) {
+        return null;
+      }
+
+      // replace commas with whitespace and remove bookending whitespace
+      points = points.replace(/,/g, ' ').trim();
+
+      points = points.split(/\s+/);
+      var parsedPoints = [], i, len;
+
+      i = 0;
+      len = points.length;
+      for (; i < len; i += 2) {
+        parsedPoints.push({
+          x: parseFloat(points[i]),
+          y: parseFloat(points[i + 1])
+        });
+      }
+
+      // odd number of points is an error
+      // if (parsedPoints.length % 2 !== 0) {
+      //   return null;
+      // }
+
+      return parsedPoints;
+    },
+
+    /**
+     * Returns CSS rules for a given SVG document
+     * @static
+     * @function
+     * @memberOf fabric
+     * @param {SVGDocument} doc SVG document to parse
+     * @return {Object} CSS rules of this document
+     */
+    getCSSRules: function(doc) {
+      var styles = doc.getElementsByTagName('style'),
+          allRules = { }, rules;
+
+      // very crude parsing of style contents
+      for (var i = 0, len = styles.length; i < len; i++) {
+        // IE9 doesn't support textContent, but provides text instead.
+        var styleContents = styles[i].textContent || styles[i].text;
+
+        // remove comments
+        styleContents = styleContents.replace(/\/\*[\s\S]*?\*\//g, '');
+        if (styleContents.trim() === '') {
+          continue;
+        }
+        rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
+        rules = rules.map(function(rule) { return rule.trim(); });
+        rules.forEach(function(rule) {
+
+          var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/),
+              ruleObj = { }, declaration = match[2].trim(),
+              propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/);
+
+          for (var i = 0, len = propertyValuePairs.length; i < len; i++) {
+            var pair = propertyValuePairs[i].split(/\s*:\s*/),
+                property = normalizeAttr(pair[0]),
+                value = normalizeValue(property, pair[1], pair[0]);
+            ruleObj[property] = value;
+          }
+          rule = match[1];
+          rule.split(',').forEach(function(_rule) {
+            _rule = _rule.replace(/^svg/i, '').trim();
+            if (_rule === '') {
+              return;
+            }
+            if (allRules[_rule]) {
+              fabric.util.object.extend(allRules[_rule], ruleObj);
+            }
+            else {
+              allRules[_rule] = fabric.util.object.clone(ruleObj);
+            }
+          });
+        });
+      }
+      return allRules;
+    },
+
+    /**
+     * Takes url corresponding to an SVG document, and parses it into a set of fabric objects.
+     * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)
+     * @memberOf fabric
+     * @param {String} url
+     * @param {Function} callback
+     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.
+     */
+    loadSVGFromURL: function(url, callback, reviver) {
+
+      url = url.replace(/^\n\s*/, '').trim();
+      svgCache.has(url, function (hasUrl) {
+        if (hasUrl) {
+          svgCache.get(url, function (value) {
+            var enlivedRecord = _enlivenCachedObject(value);
+            callback(enlivedRecord.objects, enlivedRecord.options);
+          });
+        }
+        else {
+          new fabric.util.request(url, {
+            method: 'get',
+            onComplete: onComplete
+          });
+        }
+      });
+
+      function onComplete(r) {
+
+        var xml = r.responseXML;
+        if (xml && !xml.documentElement && fabric.window.ActiveXObject && r.responseText) {
+          xml = new ActiveXObject('Microsoft.XMLDOM');
+          xml.async = 'false';
+          //IE chokes on DOCTYPE
+          xml.loadXML(r.responseText.replace(/<!DOCTYPE[\s\S]*?(\[[\s\S]*\])*?>/i, ''));
+        }
+        if (!xml || !xml.documentElement) {
+          callback && callback(null);
+        }
+
+        fabric.parseSVGDocument(xml.documentElement, function (results, options) {
+          svgCache.set(url, {
+            objects: fabric.util.array.invoke(results, 'toObject'),
+            options: options
+          });
+          callback && callback(results, options);
+        }, reviver);
+      }
+    },
+
+    /**
+     * Takes string corresponding to an SVG document, and parses it into a set of fabric objects
+     * @memberOf fabric
+     * @param {String} string
+     * @param {Function} callback
+     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.
+     */
+    loadSVGFromString: function(string, callback, reviver) {
+      string = string.trim();
+      var doc;
+      if (typeof DOMParser !== 'undefined') {
+        var parser = new DOMParser();
+        if (parser && parser.parseFromString) {
+          doc = parser.parseFromString(string, 'text/xml');
+        }
+      }
+      else if (fabric.window.ActiveXObject) {
+        doc = new ActiveXObject('Microsoft.XMLDOM');
+        doc.async = 'false';
+        // IE chokes on DOCTYPE
+        doc.loadXML(string.replace(/<!DOCTYPE[\s\S]*?(\[[\s\S]*\])*?>/i, ''));
+      }
+
+      fabric.parseSVGDocument(doc.documentElement, function (results, options) {
+        callback(results, options);
+      }, reviver);
+    },
+
+    /**
+     * Creates markup containing SVG font faces,
+     * font URLs for font faces must be collected by developers
+     * and are not extracted from the DOM by fabricjs
+     * @param {Array} objects Array of fabric objects
+     * @return {String}
+     */
+    createSVGFontFacesMarkup: function(objects) {
+      var markup = '', fontList = { }, obj, fontFamily,
+          style, row, rowIndex, _char, charIndex,
+          fontPaths = fabric.fontPaths;
+
+      for (var i = 0, len = objects.length; i < len; i++) {
+        obj = objects[i];
+        fontFamily = obj.fontFamily;
+        if (obj.type.indexOf('text') === -1 || fontList[fontFamily] || !fontPaths[fontFamily]) {
+          continue;
+        }
+        fontList[fontFamily] = true;
+        if (!obj.styles) {
+          continue;
+        }
+        style = obj.styles;
+        for (rowIndex in style) {
+          row = style[rowIndex];
+          for (charIndex in row) {
+            _char = row[charIndex];
+            fontFamily = _char.fontFamily;
+            if (!fontList[fontFamily] && fontPaths[fontFamily]) {
+              fontList[fontFamily] = true;
+            }
+          }
+        }
+      }
+
+      for (var j in fontList) {
+        markup += [
+          '\t\t@font-face {\n',
+          '\t\t\tfont-family: \'', j, '\';\n',
+          '\t\t\tsrc: url(\'', fontPaths[j], '\');\n',
+          '\t\t}\n'
+        ].join('');
+      }
+
+      if (markup) {
+        markup = [
+          '\t<style type="text/css">',
+          '<![CDATA[\n',
+          markup,
+          ']]>',
+          '</style>\n'
+        ].join('');
+      }
+
+      return markup;
+    },
+
+    /**
+     * Creates markup containing SVG referenced elements like patterns, gradients etc.
+     * @param {fabric.Canvas} canvas instance of fabric.Canvas
+     * @return {String}
+     */
+    createSVGRefElementsMarkup: function(canvas) {
+      var markup = [];
+
+      _createSVGPattern(markup, canvas, 'backgroundColor');
+      _createSVGPattern(markup, canvas, 'overlayColor');
+
+      return markup.join('');
+    }
+  });
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+fabric.ElementsParser = function(elements, callback, options, reviver) {
+  this.elements = elements;
+  this.callback = callback;
+  this.options = options;
+  this.reviver = reviver;
+  this.svgUid = (options && options.svgUid) || 0;
+};
+
+fabric.ElementsParser.prototype.parse = function() {
+  this.instances = new Array(this.elements.length);
+  this.numElements = this.elements.length;
+
+  this.createObjects();
+};
+
+fabric.ElementsParser.prototype.createObjects = function() {
+  for (var i = 0, len = this.elements.length; i < len; i++) {
+    this.elements[i].setAttribute('svgUid', this.svgUid);
+    (function(_obj, i) {
+      setTimeout(function() {
+        _obj.createObject(_obj.elements[i], i);
+      }, 0);
+    })(this, i);
+  }
+};
+
+fabric.ElementsParser.prototype.createObject = function(el, index) {
+  var klass = fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];
+  if (klass && klass.fromElement) {
+    try {
+      this._createObject(klass, el, index);
+    }
+    catch (err) {
+      fabric.log(err);
+    }
+  }
+  else {
+    this.checkIfDone();
+  }
+};
+
+fabric.ElementsParser.prototype._createObject = function(klass, el, index) {
+  if (klass.async) {
+    klass.fromElement(el, this.createCallback(index, el), this.options);
+  }
+  else {
+    var obj = klass.fromElement(el, this.options);
+    this.resolveGradient(obj, 'fill');
+    this.resolveGradient(obj, 'stroke');
+    this.reviver && this.reviver(el, obj);
+    this.instances[index] = obj;
+    this.checkIfDone();
+  }
+};
+
+fabric.ElementsParser.prototype.createCallback = function(index, el) {
+  var _this = this;
+  return function(obj) {
+    _this.resolveGradient(obj, 'fill');
+    _this.resolveGradient(obj, 'stroke');
+    _this.reviver && _this.reviver(el, obj);
+    _this.instances[index] = obj;
+    _this.checkIfDone();
+  };
+};
+
+fabric.ElementsParser.prototype.resolveGradient = function(obj, property) {
+
+  var instanceFillValue = obj.get(property);
+  if (!(/^url\(/).test(instanceFillValue)) {
+    return;
+  }
+  var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
+  if (fabric.gradientDefs[this.svgUid][gradientId]) {
+    obj.set(property,
+      fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj));
+  }
+};
+
+fabric.ElementsParser.prototype.checkIfDone = function() {
+  if (--this.numElements === 0) {
+    this.instances = this.instances.filter(function(el) {
+      // eslint-disable-next-line no-eq-null, eqeqeq
+      return el != null;
+    });
+    this.callback(this.instances);
+  }
+};
+
+
+(function(global) {
+
+  'use strict';
+
+  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */
+
+  var fabric = global.fabric || (global.fabric = { });
+
+  if (fabric.Point) {
+    fabric.warn('fabric.Point is already defined');
+    return;
+  }
+
+  fabric.Point = Point;
+
+  /**
+   * Point class
+   * @class fabric.Point
+   * @memberOf fabric
+   * @constructor
+   * @param {Number} x
+   * @param {Number} y
+   * @return {fabric.Point} thisArg
+   */
+  function Point(x, y) {
+    this.x = x;
+    this.y = y;
+  }
+
+  Point.prototype = /** @lends fabric.Point.prototype */ {
+
+    type: 'point',
+
+    constructor: Point,
+
+    /**
+     * Adds another point to this one and returns another one
+     * @param {fabric.Point} that
+     * @return {fabric.Point} new Point instance with added values
+     */
+    add: function (that) {
+      return new Point(this.x + that.x, this.y + that.y);
+    },
+
+    /**
+     * Adds another point to this one
+     * @param {fabric.Point} that
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    addEquals: function (that) {
+      this.x += that.x;
+      this.y += that.y;
+      return this;
+    },
+
+    /**
+     * Adds value to this point and returns a new one
+     * @param {Number} scalar
+     * @return {fabric.Point} new Point with added value
+     */
+    scalarAdd: function (scalar) {
+      return new Point(this.x + scalar, this.y + scalar);
+    },
+
+    /**
+     * Adds value to this point
+     * @param {Number} scalar
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    scalarAddEquals: function (scalar) {
+      this.x += scalar;
+      this.y += scalar;
+      return this;
+    },
+
+    /**
+     * Subtracts another point from this point and returns a new one
+     * @param {fabric.Point} that
+     * @return {fabric.Point} new Point object with subtracted values
+     */
+    subtract: function (that) {
+      return new Point(this.x - that.x, this.y - that.y);
+    },
+
+    /**
+     * Subtracts another point from this point
+     * @param {fabric.Point} that
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    subtractEquals: function (that) {
+      this.x -= that.x;
+      this.y -= that.y;
+      return this;
+    },
+
+    /**
+     * Subtracts value from this point and returns a new one
+     * @param {Number} scalar
+     * @return {fabric.Point}
+     */
+    scalarSubtract: function (scalar) {
+      return new Point(this.x - scalar, this.y - scalar);
+    },
+
+    /**
+     * Subtracts value from this point
+     * @param {Number} scalar
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    scalarSubtractEquals: function (scalar) {
+      this.x -= scalar;
+      this.y -= scalar;
+      return this;
+    },
+
+    /**
+     * Miltiplies this point by a value and returns a new one
+     * TODO: rename in scalarMultiply in 2.0
+     * @param {Number} scalar
+     * @return {fabric.Point}
+     */
+    multiply: function (scalar) {
+      return new Point(this.x * scalar, this.y * scalar);
+    },
+
+    /**
+     * Miltiplies this point by a value
+     * TODO: rename in scalarMultiplyEquals in 2.0
+     * @param {Number} scalar
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    multiplyEquals: function (scalar) {
+      this.x *= scalar;
+      this.y *= scalar;
+      return this;
+    },
+
+    /**
+     * Divides this point by a value and returns a new one
+     * TODO: rename in scalarDivide in 2.0
+     * @param {Number} scalar
+     * @return {fabric.Point}
+     */
+    divide: function (scalar) {
+      return new Point(this.x / scalar, this.y / scalar);
+    },
+
+    /**
+     * Divides this point by a value
+     * TODO: rename in scalarDivideEquals in 2.0
+     * @param {Number} scalar
+     * @return {fabric.Point} thisArg
+     * @chainable
+     */
+    divideEquals: function (scalar) {
+      this.x /= scalar;
+      this.y /= scalar;
+      return this;
+    },
+
+    /**
+     * Returns true if this point is equal to another one
+     * @param {fabric.Point} that
+     * @return {Boolean}
+     */
+    eq: function (that) {
+      return (this.x === that.x && this.y === that.y);
+    },
+
+    /**
+     * Returns true if this point is less than another one
+     * @param {fabric.Point} that
+     * @return {Boolean}
+     */
+    lt: function (that) {
+      return (this.x < that.x && this.y < that.y);
+    },
+
+    /**
+     * Returns true if this point is less than or equal to another one
+     * @param {fabric.Point} that
+     * @return {Boolean}
+     */
+    lte: function (that) {
+      return (this.x <= that.x && this.y <= that.y);
+    },
+
+    /**
+
+     * Returns true if this point is greater another one
+     * @param {fabric.Point} that
+     * @return {Boolean}
+     */
+    gt: function (that) {
+      return (this.x > that.x && this.y > that.y);
+    },
+
+    /**
+     * Returns true if this point is greater than or equal to another one
+     * @param {fabric.Point} that
+     * @return {Boolean}
+     */
+    gte: function (that) {
+      return (this.x >= that.x && this.y >= that.y);
+    },
+
+    /**
+     * Returns new point which is the result of linear interpolation with this one and another one
+     * @param {fabric.Point} that
+     * @param {Number} t , position of interpolation, between 0 and 1 default 0.5
+     * @return {fabric.Point}
+     */
+    lerp: function (that, t) {
+      if (typeof t === 'undefined') {
+        t = 0.5;
+      }
+      t = Math.max(Math.min(1, t), 0);
+      return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t);
+    },
+
+    /**
+     * Returns distance from this point and another one
+     * @param {fabric.Point} that
+     * @return {Number}
+     */
+    distanceFrom: function (that) {
+      var dx = this.x - that.x,
+          dy = this.y - that.y;
+      return Math.sqrt(dx * dx + dy * dy);
+    },
+
+    /**
+     * Returns the point between this point and another one
+     * @param {fabric.Point} that
+     * @return {fabric.Point}
+     */
+    midPointFrom: function (that) {
+      return this.lerp(that);
+    },
+
+    /**
+     * Returns a new point which is the min of this and another one
+     * @param {fabric.Point} that
+     * @return {fabric.Point}
+     */
+    min: function (that) {
+      return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));
+    },
+
+    /**
+     * Returns a new point which is the max of this and another one
+     * @param {fabric.Point} that
+     * @return {fabric.Point}
+     */
+    max: function (that) {
+      return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));
+    },
+
+    /**
+     * Returns string representation of this point
+     * @return {String}
+     */
+    toString: function () {
+      return this.x + ',' + this.y;
+    },
+
+    /**
+     * Sets x/y of this point
+     * @param {Number} x
+     * @param {Number} y
+     * @chainable
+     */
+    setXY: function (x, y) {
+      this.x = x;
+      this.y = y;
+      return this;
+    },
+
+    /**
+     * Sets x of this point
+     * @param {Number} x
+     * @chainable
+     */
+    setX: function (x) {
+      this.x = x;
+      return this;
+    },
+
+    /**
+     * Sets y of this point
+     * @param {Number} y
+     * @chainable
+     */
+    setY: function (y) {
+      this.y = y;
+      return this;
+    },
+
+    /**
+     * Sets x/y of this point from another point
+     * @param {fabric.Point} that
+     * @chainable
+     */
+    setFromPoint: function (that) {
+      this.x = that.x;
+      this.y = that.y;
+      return this;
+    },
+
+    /**
+     * Swaps x/y of this point and another point
+     * @param {fabric.Point} that
+     */
+    swap: function (that) {
+      var x = this.x,
+          y = this.y;
+      this.x = that.x;
+      this.y = that.y;
+      that.x = x;
+      that.y = y;
+    },
+
+    /**
+     * return a cloned instance of the point
+     * @return {fabric.Point}
+     */
+    clone: function () {
+      return new Point(this.x, this.y);
+    }
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */
+  var fabric = global.fabric || (global.fabric = { });
+
+  if (fabric.Intersection) {
+    fabric.warn('fabric.Intersection is already defined');
+    return;
+  }
+
+  /**
+   * Intersection class
+   * @class fabric.Intersection
+   * @memberOf fabric
+   * @constructor
+   */
+  function Intersection(status) {
+    this.status = status;
+    this.points = [];
+  }
+
+  fabric.Intersection = Intersection;
+
+  fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ {
+
+    constructor: Intersection,
+
+    /**
+     * Appends a point to intersection
+     * @param {fabric.Point} point
+     * @return {fabric.Intersection} thisArg
+     * @chainable
+     */
+    appendPoint: function (point) {
+      this.points.push(point);
+      return this;
+    },
+
+    /**
+     * Appends points to intersection
+     * @param {Array} points
+     * @return {fabric.Intersection} thisArg
+     * @chainable
+     */
+    appendPoints: function (points) {
+      this.points = this.points.concat(points);
+      return this;
+    }
+  };
+
+  /**
+   * Checks if one line intersects another
+   * TODO: rename in intersectSegmentSegment
+   * @static
+   * @param {fabric.Point} a1
+   * @param {fabric.Point} a2
+   * @param {fabric.Point} b1
+   * @param {fabric.Point} b2
+   * @return {fabric.Intersection}
+   */
+  fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) {
+    var result,
+        uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),
+        ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),
+        uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
+    if (uB !== 0) {
+      var ua = uaT / uB,
+          ub = ubT / uB;
+      if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
+        result = new Intersection('Intersection');
+        result.appendPoint(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)));
+      }
+      else {
+        result = new Intersection();
+      }
+    }
+    else {
+      if (uaT === 0 || ubT === 0) {
+        result = new Intersection('Coincident');
+      }
+      else {
+        result = new Intersection('Parallel');
+      }
+    }
+    return result;
+  };
+
+  /**
+   * Checks if line intersects polygon
+   * TODO: rename in intersectSegmentPolygon
+   * fix detection of coincident
+   * @static
+   * @param {fabric.Point} a1
+   * @param {fabric.Point} a2
+   * @param {Array} points
+   * @return {fabric.Intersection}
+   */
+  fabric.Intersection.intersectLinePolygon = function(a1, a2, points) {
+    var result = new Intersection(),
+        length = points.length,
+        b1, b2, inter;
+
+    for (var i = 0; i < length; i++) {
+      b1 = points[i];
+      b2 = points[(i + 1) % length];
+      inter = Intersection.intersectLineLine(a1, a2, b1, b2);
+
+      result.appendPoints(inter.points);
+    }
+    if (result.points.length > 0) {
+      result.status = 'Intersection';
+    }
+    return result;
+  };
+
+  /**
+   * Checks if polygon intersects another polygon
+   * @static
+   * @param {Array} points1
+   * @param {Array} points2
+   * @return {fabric.Intersection}
+   */
+  fabric.Intersection.intersectPolygonPolygon = function (points1, points2) {
+    var result = new Intersection(),
+        length = points1.length;
+
+    for (var i = 0; i < length; i++) {
+      var a1 = points1[i],
+          a2 = points1[(i + 1) % length],
+          inter = Intersection.intersectLinePolygon(a1, a2, points2);
+
+      result.appendPoints(inter.points);
+    }
+    if (result.points.length > 0) {
+      result.status = 'Intersection';
+    }
+    return result;
+  };
+
+  /**
+   * Checks if polygon intersects rectangle
+   * @static
+   * @param {Array} points
+   * @param {fabric.Point} r1
+   * @param {fabric.Point} r2
+   * @return {fabric.Intersection}
+   */
+  fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) {
+    var min = r1.min(r2),
+        max = r1.max(r2),
+        topRight = new fabric.Point(max.x, min.y),
+        bottomLeft = new fabric.Point(min.x, max.y),
+        inter1 = Intersection.intersectLinePolygon(min, topRight, points),
+        inter2 = Intersection.intersectLinePolygon(topRight, max, points),
+        inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points),
+        inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points),
+        result = new Intersection();
+
+    result.appendPoints(inter1.points);
+    result.appendPoints(inter2.points);
+    result.appendPoints(inter3.points);
+    result.appendPoints(inter4.points);
+
+    if (result.points.length > 0) {
+      result.status = 'Intersection';
+    }
+    return result;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { });
+
+  if (fabric.Color) {
+    fabric.warn('fabric.Color is already defined.');
+    return;
+  }
+
+  /**
+   * Color class
+   * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;
+   * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.
+   *
+   * @class fabric.Color
+   * @param {String} color optional in hex or rgb(a) or hsl format or from known color list
+   * @return {fabric.Color} thisArg
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}
+   */
+  function Color(color) {
+    if (!color) {
+      this.setSource([0, 0, 0, 1]);
+    }
+    else {
+      this._tryParsingColor(color);
+    }
+  }
+
+  fabric.Color = Color;
+
+  fabric.Color.prototype = /** @lends fabric.Color.prototype */ {
+
+    /**
+     * @private
+     * @param {String|Array} color Color value to parse
+     */
+    _tryParsingColor: function(color) {
+      var source;
+
+      if (color in Color.colorNameMap) {
+        color = Color.colorNameMap[color];
+      }
+
+      if (color === 'transparent') {
+        source = [255, 255, 255, 0];
+      }
+
+      if (!source) {
+        source = Color.sourceFromHex(color);
+      }
+      if (!source) {
+        source = Color.sourceFromRgb(color);
+      }
+      if (!source) {
+        source = Color.sourceFromHsl(color);
+      }
+      if (!source) {
+        //if color is not recognize let's make black as canvas does
+        source = [0, 0, 0, 1];
+      }
+      if (source) {
+        this.setSource(source);
+      }
+    },
+
+    /**
+     * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
+     * @private
+     * @param {Number} r Red color value
+     * @param {Number} g Green color value
+     * @param {Number} b Blue color value
+     * @return {Array} Hsl color
+     */
+    _rgbToHsl: function(r, g, b) {
+      r /= 255; g /= 255; b /= 255;
+
+      var h, s, l,
+          max = fabric.util.array.max([r, g, b]),
+          min = fabric.util.array.min([r, g, b]);
+
+      l = (max + min) / 2;
+
+      if (max === min) {
+        h = s = 0; // achromatic
+      }
+      else {
+        var d = max - min;
+        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+        switch (max) {
+          case r:
+            h = (g - b) / d + (g < b ? 6 : 0);
+            break;
+          case g:
+            h = (b - r) / d + 2;
+            break;
+          case b:
+            h = (r - g) / d + 4;
+            break;
+        }
+        h /= 6;
+      }
+
+      return [
+        Math.round(h * 360),
+        Math.round(s * 100),
+        Math.round(l * 100)
+      ];
+    },
+
+    /**
+     * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])
+     * @return {Array}
+     */
+    getSource: function() {
+      return this._source;
+    },
+
+    /**
+     * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])
+     * @param {Array} source
+     */
+    setSource: function(source) {
+      this._source = source;
+    },
+
+    /**
+     * Returns color represenation in RGB format
+     * @return {String} ex: rgb(0-255,0-255,0-255)
+     */
+    toRgb: function() {
+      var source = this.getSource();
+      return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';
+    },
+
+    /**
+     * Returns color represenation in RGBA format
+     * @return {String} ex: rgba(0-255,0-255,0-255,0-1)
+     */
+    toRgba: function() {
+      var source = this.getSource();
+      return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';
+    },
+
+    /**
+     * Returns color represenation in HSL format
+     * @return {String} ex: hsl(0-360,0%-100%,0%-100%)
+     */
+    toHsl: function() {
+      var source = this.getSource(),
+          hsl = this._rgbToHsl(source[0], source[1], source[2]);
+
+      return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';
+    },
+
+    /**
+     * Returns color represenation in HSLA format
+     * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)
+     */
+    toHsla: function() {
+      var source = this.getSource(),
+          hsl = this._rgbToHsl(source[0], source[1], source[2]);
+
+      return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';
+    },
+
+    /**
+     * Returns color represenation in HEX format
+     * @return {String} ex: FF5555
+     */
+    toHex: function() {
+      var source = this.getSource(), r, g, b;
+
+      r = source[0].toString(16);
+      r = (r.length === 1) ? ('0' + r) : r;
+
+      g = source[1].toString(16);
+      g = (g.length === 1) ? ('0' + g) : g;
+
+      b = source[2].toString(16);
+      b = (b.length === 1) ? ('0' + b) : b;
+
+      return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();
+    },
+
+    /**
+     * Gets value of alpha channel for this color
+     * @return {Number} 0-1
+     */
+    getAlpha: function() {
+      return this.getSource()[3];
+    },
+
+    /**
+     * Sets value of alpha channel for this color
+     * @param {Number} alpha Alpha value 0-1
+     * @return {fabric.Color} thisArg
+     */
+    setAlpha: function(alpha) {
+      var source = this.getSource();
+      source[3] = alpha;
+      this.setSource(source);
+      return this;
+    },
+
+    /**
+     * Transforms color to its grayscale representation
+     * @return {fabric.Color} thisArg
+     */
+    toGrayscale: function() {
+      var source = this.getSource(),
+          average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),
+          currentAlpha = source[3];
+      this.setSource([average, average, average, currentAlpha]);
+      return this;
+    },
+
+    /**
+     * Transforms color to its black and white representation
+     * @param {Number} threshold
+     * @return {fabric.Color} thisArg
+     */
+    toBlackWhite: function(threshold) {
+      var source = this.getSource(),
+          average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),
+          currentAlpha = source[3];
+
+      threshold = threshold || 127;
+
+      average = (Number(average) < Number(threshold)) ? 0 : 255;
+      this.setSource([average, average, average, currentAlpha]);
+      return this;
+    },
+
+    /**
+     * Overlays color with another color
+     * @param {String|fabric.Color} otherColor
+     * @return {fabric.Color} thisArg
+     */
+    overlayWith: function(otherColor) {
+      if (!(otherColor instanceof Color)) {
+        otherColor = new Color(otherColor);
+      }
+
+      var result = [],
+          alpha = this.getAlpha(),
+          otherAlpha = 0.5,
+          source = this.getSource(),
+          otherSource = otherColor.getSource();
+
+      for (var i = 0; i < 3; i++) {
+        result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));
+      }
+
+      result[3] = alpha;
+      this.setSource(result);
+      return this;
+    }
+  };
+
+  /**
+   * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))
+   * @static
+   * @field
+   * @memberOf fabric.Color
+   */
+   // eslint-disable-next-line max-len
+  fabric.Color.reRGBa = /^rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
+
+  /**
+   * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))
+   * @static
+   * @field
+   * @memberOf fabric.Color
+   */
+  fabric.Color.reHSLa = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
+
+  /**
+   * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff)
+   * @static
+   * @field
+   * @memberOf fabric.Color
+   */
+  fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;
+
+  /**
+   * Map of the 17 basic color names with HEX code
+   * @static
+   * @field
+   * @memberOf fabric.Color
+   * @see: http://www.w3.org/TR/CSS2/syndata.html#color-units
+   */
+  fabric.Color.colorNameMap = {
+    aqua:    '#00FFFF',
+    black:   '#000000',
+    blue:    '#0000FF',
+    fuchsia: '#FF00FF',
+    gray:    '#808080',
+    grey:    '#808080',
+    green:   '#008000',
+    lime:    '#00FF00',
+    maroon:  '#800000',
+    navy:    '#000080',
+    olive:   '#808000',
+    orange:  '#FFA500',
+    purple:  '#800080',
+    red:     '#FF0000',
+    silver:  '#C0C0C0',
+    teal:    '#008080',
+    white:   '#FFFFFF',
+    yellow:  '#FFFF00'
+  };
+
+  /**
+   * @private
+   * @param {Number} p
+   * @param {Number} q
+   * @param {Number} t
+   * @return {Number}
+   */
+  function hue2rgb(p, q, t) {
+    if (t < 0) {
+      t += 1;
+    }
+    if (t > 1) {
+      t -= 1;
+    }
+    if (t < 1 / 6) {
+      return p + (q - p) * 6 * t;
+    }
+    if (t < 1 / 2) {
+      return q;
+    }
+    if (t < 2 / 3) {
+      return p + (q - p) * (2 / 3 - t) * 6;
+    }
+    return p;
+  }
+
+  /**
+   * Returns new color object, when given a color in RGB format
+   * @memberOf fabric.Color
+   * @param {String} color Color value ex: rgb(0-255,0-255,0-255)
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromRgb = function(color) {
+    return Color.fromSource(Color.sourceFromRgb(color));
+  };
+
+  /**
+   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format
+   * @memberOf fabric.Color
+   * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)
+   * @return {Array} source
+   */
+  fabric.Color.sourceFromRgb = function(color) {
+    var match = color.match(Color.reRGBa);
+    if (match) {
+      var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),
+          g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),
+          b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);
+
+      return [
+        parseInt(r, 10),
+        parseInt(g, 10),
+        parseInt(b, 10),
+        match[4] ? parseFloat(match[4]) : 1
+      ];
+    }
+  };
+
+  /**
+   * Returns new color object, when given a color in RGBA format
+   * @static
+   * @function
+   * @memberOf fabric.Color
+   * @param {String} color
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromRgba = Color.fromRgb;
+
+  /**
+   * Returns new color object, when given a color in HSL format
+   * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)
+   * @memberOf fabric.Color
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromHsl = function(color) {
+    return Color.fromSource(Color.sourceFromHsl(color));
+  };
+
+  /**
+   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.
+   * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
+   * @memberOf fabric.Color
+   * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)
+   * @return {Array} source
+   * @see http://http://www.w3.org/TR/css3-color/#hsl-color
+   */
+  fabric.Color.sourceFromHsl = function(color) {
+    var match = color.match(Color.reHSLa);
+    if (!match) {
+      return;
+    }
+
+    var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,
+        s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),
+        l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),
+        r, g, b;
+
+    if (s === 0) {
+      r = g = b = l;
+    }
+    else {
+      var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,
+          p = l * 2 - q;
+
+      r = hue2rgb(p, q, h + 1 / 3);
+      g = hue2rgb(p, q, h);
+      b = hue2rgb(p, q, h - 1 / 3);
+    }
+
+    return [
+      Math.round(r * 255),
+      Math.round(g * 255),
+      Math.round(b * 255),
+      match[4] ? parseFloat(match[4]) : 1
+    ];
+  };
+
+  /**
+   * Returns new color object, when given a color in HSLA format
+   * @static
+   * @function
+   * @memberOf fabric.Color
+   * @param {String} color
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromHsla = Color.fromHsl;
+
+  /**
+   * Returns new color object, when given a color in HEX format
+   * @static
+   * @memberOf fabric.Color
+   * @param {String} color Color value ex: FF5555
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromHex = function(color) {
+    return Color.fromSource(Color.sourceFromHex(color));
+  };
+
+  /**
+   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format
+   * @static
+   * @memberOf fabric.Color
+   * @param {String} color ex: FF5555 or FF5544CC (RGBa)
+   * @return {Array} source
+   */
+  fabric.Color.sourceFromHex = function(color) {
+    if (color.match(Color.reHex)) {
+      var value = color.slice(color.indexOf('#') + 1),
+          isShortNotation = (value.length === 3 || value.length === 4),
+          isRGBa = (value.length === 8 || value.length === 4),
+          r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),
+          g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),
+          b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6),
+          a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF';
+
+      return [
+        parseInt(r, 16),
+        parseInt(g, 16),
+        parseInt(b, 16),
+        parseFloat((parseInt(a, 16) / 255).toFixed(2))
+      ];
+    }
+  };
+
+  /**
+   * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])
+   * @static
+   * @memberOf fabric.Color
+   * @param {Array} source
+   * @return {fabric.Color}
+   */
+  fabric.Color.fromSource = function(source) {
+    var oColor = new Color();
+    oColor.setSource(source);
+    return oColor;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function() {
+
+  /* _FROM_SVG_START_ */
+  function getColorStop(el) {
+    var style = el.getAttribute('style'),
+        offset = el.getAttribute('offset') || 0,
+        color, colorAlpha, opacity;
+
+    // convert percents to absolute values
+    offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);
+    offset = offset < 0 ? 0 : offset > 1 ? 1 : offset;
+    if (style) {
+      var keyValuePairs = style.split(/\s*;\s*/);
+
+      if (keyValuePairs[keyValuePairs.length - 1] === '') {
+        keyValuePairs.pop();
+      }
+
+      for (var i = keyValuePairs.length; i--; ) {
+
+        var split = keyValuePairs[i].split(/\s*:\s*/),
+            key = split[0].trim(),
+            value = split[1].trim();
+
+        if (key === 'stop-color') {
+          color = value;
+        }
+        else if (key === 'stop-opacity') {
+          opacity = value;
+        }
+      }
+    }
+
+    if (!color) {
+      color = el.getAttribute('stop-color') || 'rgb(0,0,0)';
+    }
+    if (!opacity) {
+      opacity = el.getAttribute('stop-opacity');
+    }
+
+    color = new fabric.Color(color);
+    colorAlpha = color.getAlpha();
+    opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);
+    opacity *= colorAlpha;
+
+    return {
+      offset: offset,
+      color: color.toRgb(),
+      opacity: opacity
+    };
+  }
+
+  function getLinearCoords(el) {
+    return {
+      x1: el.getAttribute('x1') || 0,
+      y1: el.getAttribute('y1') || 0,
+      x2: el.getAttribute('x2') || '100%',
+      y2: el.getAttribute('y2') || 0
+    };
+  }
+
+  function getRadialCoords(el) {
+    return {
+      x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',
+      y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',
+      r1: 0,
+      x2: el.getAttribute('cx') || '50%',
+      y2: el.getAttribute('cy') || '50%',
+      r2: el.getAttribute('r') || '50%'
+    };
+  }
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Gradient class
+   * @class fabric.Gradient
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#gradients}
+   * @see {@link fabric.Gradient#initialize} for constructor definition
+   */
+  fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {
+
+    /**
+     * Horizontal offset for aligning gradients coming from SVG when outside pathgroups
+     * @type Number
+     * @default 0
+     */
+    offsetX: 0,
+
+    /**
+     * Vertical offset for aligning gradients coming from SVG when outside pathgroups
+     * @type Number
+     * @default 0
+     */
+    offsetY: 0,
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops
+     * @return {fabric.Gradient} thisArg
+     */
+    initialize: function(options) {
+      options || (options = { });
+
+      var coords = { };
+
+      this.id = fabric.Object.__uid++;
+      this.type = options.type || 'linear';
+
+      coords = {
+        x1: options.coords.x1 || 0,
+        y1: options.coords.y1 || 0,
+        x2: options.coords.x2 || 0,
+        y2: options.coords.y2 || 0
+      };
+
+      if (this.type === 'radial') {
+        coords.r1 = options.coords.r1 || 0;
+        coords.r2 = options.coords.r2 || 0;
+      }
+      this.coords = coords;
+      this.colorStops = options.colorStops.slice();
+      if (options.gradientTransform) {
+        this.gradientTransform = options.gradientTransform;
+      }
+      this.offsetX = options.offsetX || this.offsetX;
+      this.offsetY = options.offsetY || this.offsetY;
+    },
+
+    /**
+     * Adds another colorStop
+     * @param {Object} colorStop Object with offset and color
+     * @return {fabric.Gradient} thisArg
+     */
+    addColorStop: function(colorStop) {
+      for (var position in colorStop) {
+        var color = new fabric.Color(colorStop[position]);
+        this.colorStops.push({
+          offset: position,
+          color: color.toRgb(),
+          opacity: color.getAlpha()
+        });
+      }
+      return this;
+    },
+
+    /**
+     * Returns object representation of a gradient
+     * @return {Object}
+     */
+    toObject: function() {
+      return {
+        type: this.type,
+        coords: this.coords,
+        colorStops: this.colorStops,
+        offsetX: this.offsetX,
+        offsetY: this.offsetY,
+        gradientTransform: this.gradientTransform ? this.gradientTransform.concat() : this.gradientTransform
+      };
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an gradient
+     * @param {Object} object Object to create a gradient for
+     * @return {String} SVG representation of an gradient (linear/radial)
+     */
+    toSVG: function(object) {
+      var coords = fabric.util.object.clone(this.coords),
+          markup, commonAttributes;
+
+      // colorStops must be sorted ascending
+      this.colorStops.sort(function(a, b) {
+        return a.offset - b.offset;
+      });
+
+      if (!(object.group && object.group.type === 'path-group')) {
+        for (var prop in coords) {
+          if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
+            coords[prop] += this.offsetX - object.width / 2;
+          }
+          else if (prop === 'y1' || prop === 'y2') {
+            coords[prop] += this.offsetY - object.height / 2;
+          }
+        }
+      }
+
+      commonAttributes = 'id="SVGID_' + this.id +
+                     '" gradientUnits="userSpaceOnUse"';
+      if (this.gradientTransform) {
+        commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" ';
+      }
+      if (this.type === 'linear') {
+        markup = [
+          '<linearGradient ',
+          commonAttributes,
+          ' x1="', coords.x1,
+          '" y1="', coords.y1,
+          '" x2="', coords.x2,
+          '" y2="', coords.y2,
+          '">\n'
+        ];
+      }
+      else if (this.type === 'radial') {
+        markup = [
+          '<radialGradient ',
+          commonAttributes,
+          ' cx="', coords.x2,
+          '" cy="', coords.y2,
+          '" r="', coords.r2,
+          '" fx="', coords.x1,
+          '" fy="', coords.y1,
+          '">\n'
+        ];
+      }
+
+      for (var i = 0; i < this.colorStops.length; i++) {
+        markup.push(
+          '<stop ',
+            'offset="', (this.colorStops[i].offset * 100) + '%',
+            '" style="stop-color:', this.colorStops[i].color,
+            (this.colorStops[i].opacity !== null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
+          '"/>\n'
+        );
+      }
+
+      markup.push((this.type === 'linear' ? '</linearGradient>\n' : '</radialGradient>\n'));
+
+      return markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns an instance of CanvasGradient
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Object} object
+     * @return {CanvasGradient}
+     */
+    toLive: function(ctx, object) {
+      var gradient, prop, coords = fabric.util.object.clone(this.coords);
+
+      if (!this.type) {
+        return;
+      }
+
+      if (object.group && object.group.type === 'path-group') {
+        for (prop in coords) {
+          if (prop === 'x1' || prop === 'x2') {
+            coords[prop] += -this.offsetX + object.width / 2;
+          }
+          else if (prop === 'y1' || prop === 'y2') {
+            coords[prop] += -this.offsetY + object.height / 2;
+          }
+        }
+      }
+
+      if (this.type === 'linear') {
+        gradient = ctx.createLinearGradient(
+          coords.x1, coords.y1, coords.x2, coords.y2);
+      }
+      else if (this.type === 'radial') {
+        gradient = ctx.createRadialGradient(
+          coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);
+      }
+
+      for (var i = 0, len = this.colorStops.length; i < len; i++) {
+        var color = this.colorStops[i].color,
+            opacity = this.colorStops[i].opacity,
+            offset = this.colorStops[i].offset;
+
+        if (typeof opacity !== 'undefined') {
+          color = new fabric.Color(color).setAlpha(opacity).toRgba();
+        }
+        gradient.addColorStop(parseFloat(offset), color);
+      }
+
+      return gradient;
+    }
+  });
+
+  fabric.util.object.extend(fabric.Gradient, {
+
+    /* _FROM_SVG_START_ */
+    /**
+     * Returns {@link fabric.Gradient} instance from an SVG element
+     * @static
+     * @memberOf fabric.Gradient
+     * @param {SVGGradientElement} el SVG gradient element
+     * @param {fabric.Object} instance
+     * @return {fabric.Gradient} Gradient instance
+     * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
+     * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
+     */
+    fromElement: function(el, instance) {
+
+      /**
+       *  @example:
+       *
+       *  <linearGradient id="linearGrad1">
+       *    <stop offset="0%" stop-color="white"/>
+       *    <stop offset="100%" stop-color="black"/>
+       *  </linearGradient>
+       *
+       *  OR
+       *
+       *  <linearGradient id="linearGrad2">
+       *    <stop offset="0" style="stop-color:rgb(255,255,255)"/>
+       *    <stop offset="1" style="stop-color:rgb(0,0,0)"/>
+       *  </linearGradient>
+       *
+       *  OR
+       *
+       *  <radialGradient id="radialGrad1">
+       *    <stop offset="0%" stop-color="white" stop-opacity="1" />
+       *    <stop offset="50%" stop-color="black" stop-opacity="0.5" />
+       *    <stop offset="100%" stop-color="white" stop-opacity="1" />
+       *  </radialGradient>
+       *
+       *  OR
+       *
+       *  <radialGradient id="radialGrad2">
+       *    <stop offset="0" stop-color="rgb(255,255,255)" />
+       *    <stop offset="0.5" stop-color="rgb(0,0,0)" />
+       *    <stop offset="1" stop-color="rgb(255,255,255)" />
+       *  </radialGradient>
+       *
+       */
+
+      var colorStopEls = el.getElementsByTagName('stop'),
+          type,
+          gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',
+          gradientTransform = el.getAttribute('gradientTransform'),
+          colorStops = [],
+          coords, ellipseMatrix;
+
+      if (el.nodeName === 'linearGradient' || el.nodeName === 'LINEARGRADIENT') {
+        type = 'linear';
+      }
+      else {
+        type = 'radial';
+      }
+
+      if (type === 'linear') {
+        coords = getLinearCoords(el);
+      }
+      else if (type === 'radial') {
+        coords = getRadialCoords(el);
+      }
+
+      for (var i = colorStopEls.length; i--; ) {
+        colorStops.push(getColorStop(colorStopEls[i]));
+      }
+
+      ellipseMatrix = _convertPercentUnitsToValues(instance, coords, gradientUnits);
+
+      var gradient = new fabric.Gradient({
+        type: type,
+        coords: coords,
+        colorStops: colorStops,
+        offsetX: -instance.left,
+        offsetY: -instance.top
+      });
+
+      if (gradientTransform || ellipseMatrix !== '') {
+        gradient.gradientTransform = fabric.parseTransformAttribute((gradientTransform || '') + ellipseMatrix);
+      }
+      return gradient;
+    },
+    /* _FROM_SVG_END_ */
+
+    /**
+     * Returns {@link fabric.Gradient} instance from its object representation
+     * @static
+     * @memberOf fabric.Gradient
+     * @param {Object} obj
+     * @param {Object} [options] Options object
+     */
+    forObject: function(obj, options) {
+      options || (options = { });
+      _convertPercentUnitsToValues(obj, options.coords, 'userSpaceOnUse');
+      return new fabric.Gradient(options);
+    }
+  });
+
+  /**
+   * @private
+   */
+  function _convertPercentUnitsToValues(object, options, gradientUnits) {
+    var propValue, addFactor = 0, multFactor = 1, ellipseMatrix = '';
+    for (var prop in options) {
+      if (options[prop] === 'Infinity') {
+        options[prop] = 1;
+      }
+      else if (options[prop] === '-Infinity') {
+        options[prop] = 0;
+      }
+      propValue = parseFloat(options[prop], 10);
+      if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
+        multFactor = 0.01;
+      }
+      else {
+        multFactor = 1;
+      }
+      if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
+        multFactor *= gradientUnits === 'objectBoundingBox' ? object.width : 1;
+        addFactor = gradientUnits === 'objectBoundingBox' ? object.left || 0 : 0;
+      }
+      else if (prop === 'y1' || prop === 'y2') {
+        multFactor *= gradientUnits === 'objectBoundingBox' ? object.height : 1;
+        addFactor = gradientUnits === 'objectBoundingBox' ? object.top || 0 : 0;
+      }
+      options[prop] = propValue * multFactor + addFactor;
+    }
+    if (object.type === 'ellipse' &&
+        options.r2 !== null &&
+        gradientUnits === 'objectBoundingBox' &&
+        object.rx !== object.ry) {
+
+      var scaleFactor = object.ry / object.rx;
+      ellipseMatrix = ' scale(1, ' + scaleFactor + ')';
+      if (options.y1) {
+        options.y1 /= scaleFactor;
+      }
+      if (options.y2) {
+        options.y2 /= scaleFactor;
+      }
+    }
+    return ellipseMatrix;
+  }
+})();
+
+
+/**
+ * Pattern class
+ * @class fabric.Pattern
+ * @see {@link http://fabricjs.com/patterns|Pattern demo}
+ * @see {@link http://fabricjs.com/dynamic-patterns|DynamicPattern demo}
+ * @see {@link fabric.Pattern#initialize} for constructor definition
+ */
+fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ {
+
+  /**
+   * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)
+   * @type String
+   * @default
+   */
+  repeat: 'repeat',
+
+  /**
+   * Pattern horizontal offset from object's left/top corner
+   * @type Number
+   * @default
+   */
+  offsetX: 0,
+
+  /**
+   * Pattern vertical offset from object's left/top corner
+   * @type Number
+   * @default
+   */
+  offsetY: 0,
+
+  /**
+   * Constructor
+   * @param {Object} [options] Options object
+   * @return {fabric.Pattern} thisArg
+   */
+  initialize: function(options) {
+    options || (options = { });
+
+    this.id = fabric.Object.__uid++;
+
+    if (options.source) {
+      if (typeof options.source === 'string') {
+        // function string
+        if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') {
+          this.source = new Function(fabric.util.getFunctionBody(options.source));
+        }
+        else {
+          // img src string
+          var _this = this;
+          this.source = fabric.util.createImage();
+          fabric.util.loadImage(options.source, function(img) {
+            _this.source = img;
+          });
+        }
+      }
+      else {
+        // img element
+        this.source = options.source;
+      }
+    }
+    if (options.repeat) {
+      this.repeat = options.repeat;
+    }
+    if (options.offsetX) {
+      this.offsetX = options.offsetX;
+    }
+    if (options.offsetY) {
+      this.offsetY = options.offsetY;
+    }
+  },
+
+  /**
+   * Returns object representation of a pattern
+   * @return {Object} Object representation of a pattern instance
+   */
+  toObject: function() {
+
+    var source;
+
+    // callback
+    if (typeof this.source === 'function') {
+      source = String(this.source);
+    }
+    // <img> element
+    else if (typeof this.source.src === 'string') {
+      source = this.source.src;
+    }
+    // <canvas> element
+    else if (typeof this.source === 'object' && this.source.toDataURL) {
+      source = this.source.toDataURL();
+    }
+
+    return {
+      source: source,
+      repeat: this.repeat,
+      offsetX: this.offsetX,
+      offsetY: this.offsetY
+    };
+  },
+
+  /* _TO_SVG_START_ */
+  /**
+   * Returns SVG representation of a pattern
+   * @param {fabric.Object} object
+   * @return {String} SVG representation of a pattern
+   */
+  toSVG: function(object) {
+    var patternSource = typeof this.source === 'function' ? this.source() : this.source,
+        patternWidth = patternSource.width / object.getWidth(),
+        patternHeight = patternSource.height / object.getHeight(),
+        patternOffsetX = this.offsetX / object.getWidth(),
+        patternOffsetY = this.offsetY / object.getHeight(),
+        patternImgSrc = '';
+    if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') {
+      patternHeight = 1;
+    }
+    if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') {
+      patternWidth = 1;
+    }
+    if (patternSource.src) {
+      patternImgSrc = patternSource.src;
+    }
+    else if (patternSource.toDataURL) {
+      patternImgSrc = patternSource.toDataURL();
+    }
+
+    return '<pattern id="SVGID_' + this.id +
+                  '" x="' + patternOffsetX +
+                  '" y="' + patternOffsetY +
+                  '" width="' + patternWidth +
+                  '" height="' + patternHeight + '">\n' +
+             '<image x="0" y="0"' +
+                    ' width="' + patternSource.width +
+                    '" height="' + patternSource.height +
+                    '" xlink:href="' + patternImgSrc +
+             '"></image>\n' +
+           '</pattern>\n';
+  },
+  /* _TO_SVG_END_ */
+
+  /**
+   * Returns an instance of CanvasPattern
+   * @param {CanvasRenderingContext2D} ctx Context to create pattern
+   * @return {CanvasPattern}
+   */
+  toLive: function(ctx) {
+    var source = typeof this.source === 'function'
+      ? this.source()
+      : this.source;
+
+    // if the image failed to load, return, and allow rest to continue loading
+    if (!source) {
+      return '';
+    }
+
+    // if an image
+    if (typeof source.src !== 'undefined') {
+      if (!source.complete) {
+        return '';
+      }
+      if (source.naturalWidth === 0 || source.naturalHeight === 0) {
+        return '';
+      }
+    }
+    return ctx.createPattern(source, this.repeat);
+  }
+});
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      toFixed = fabric.util.toFixed;
+
+  if (fabric.Shadow) {
+    fabric.warn('fabric.Shadow is already defined.');
+    return;
+  }
+
+  /**
+   * Shadow class
+   * @class fabric.Shadow
+   * @see {@link http://fabricjs.com/shadows|Shadow demo}
+   * @see {@link fabric.Shadow#initialize} for constructor definition
+   */
+  fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {
+
+    /**
+     * Shadow color
+     * @type String
+     * @default
+     */
+    color: 'rgb(0,0,0)',
+
+    /**
+     * Shadow blur
+     * @type Number
+     */
+    blur: 0,
+
+    /**
+     * Shadow horizontal offset
+     * @type Number
+     * @default
+     */
+    offsetX: 0,
+
+    /**
+     * Shadow vertical offset
+     * @type Number
+     * @default
+     */
+    offsetY: 0,
+
+    /**
+     * Whether the shadow should affect stroke operations
+     * @type Boolean
+     * @default
+     */
+    affectStroke: false,
+
+    /**
+     * Indicates whether toObject should include default values
+     * @type Boolean
+     * @default
+     */
+    includeDefaultValues: true,
+
+    /**
+     * Constructor
+     * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetX properties or string (e.g. "rgba(0,0,0,0.2) 2px 2px 10px, "2px 2px 10px rgba(0,0,0,0.2)")
+     * @return {fabric.Shadow} thisArg
+     */
+    initialize: function(options) {
+
+      if (typeof options === 'string') {
+        options = this._parseShadow(options);
+      }
+
+      for (var prop in options) {
+        this[prop] = options[prop];
+      }
+
+      this.id = fabric.Object.__uid++;
+    },
+
+    /**
+     * @private
+     * @param {String} shadow Shadow value to parse
+     * @return {Object} Shadow object with color, offsetX, offsetY and blur
+     */
+    _parseShadow: function(shadow) {
+      var shadowStr = shadow.trim(),
+          offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [],
+          color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)';
+
+      return {
+        color: color.trim(),
+        offsetX: parseInt(offsetsAndBlur[1], 10) || 0,
+        offsetY: parseInt(offsetsAndBlur[2], 10) || 0,
+        blur: parseInt(offsetsAndBlur[3], 10) || 0
+      };
+    },
+
+    /**
+     * Returns a string representation of an instance
+     * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow
+     * @return {String} Returns CSS3 text-shadow declaration
+     */
+    toString: function() {
+      return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of a shadow
+     * @param {fabric.Object} object
+     * @return {String} SVG representation of a shadow
+     */
+    toSVG: function(object) {
+      var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
+          offset = fabric.util.rotateVector(
+            { x: this.offsetX, y: this.offsetY },
+            fabric.util.degreesToRadians(-object.angle)),
+          BLUR_BOX = 20;
+
+      if (object.width && object.height) {
+        //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
+        // we add some extra space to filter box to contain the blur ( 20 )
+        fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
+        fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
+      }
+      if (object.flipX) {
+        offset.x *= -1;
+      }
+      if (object.flipY) {
+        offset.y *= -1;
+      }
+      return (
+        '<filter id="SVGID_' + this.id + '" y="-' + fBoxY + '%" height="' + (100 + 2 * fBoxY) + '%" ' +
+          'x="-' + fBoxX + '%" width="' + (100 + 2 * fBoxX) + '%" ' + '>\n' +
+          '\t<feGaussianBlur in="SourceAlpha" stdDeviation="' +
+            toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '"></feGaussianBlur>\n' +
+          '\t<feOffset dx="' + toFixed(offset.x, NUM_FRACTION_DIGITS) +
+          '" dy="' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '" result="oBlur" ></feOffset>\n' +
+          '\t<feFlood flood-color="' + this.color + '"/>\n' +
+          '\t<feComposite in2="oBlur" operator="in" />\n' +
+          '\t<feMerge>\n' +
+            '\t\t<feMergeNode></feMergeNode>\n' +
+            '\t\t<feMergeNode in="SourceGraphic"></feMergeNode>\n' +
+          '\t</feMerge>\n' +
+        '</filter>\n');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns object representation of a shadow
+     * @return {Object} Object representation of a shadow instance
+     */
+    toObject: function() {
+      if (this.includeDefaultValues) {
+        return {
+          color: this.color,
+          blur: this.blur,
+          offsetX: this.offsetX,
+          offsetY: this.offsetY,
+          affectStroke: this.affectStroke
+        };
+      }
+      var obj = { }, proto = fabric.Shadow.prototype;
+
+      ['color', 'blur', 'offsetX', 'offsetY', 'affectStroke'].forEach(function(prop) {
+        if (this[prop] !== proto[prop]) {
+          obj[prop] = this[prop];
+        }
+      }, this);
+
+      return obj;
+    }
+  });
+
+  /**
+   * Regex matching shadow offsetX, offsetY and blur (ex: "2px 2px 10px rgba(0,0,0,0.2)", "rgb(0,255,0) 2px 2px")
+   * @static
+   * @field
+   * @memberOf fabric.Shadow
+   */
+  // eslint-disable-next-line max-len
+  fabric.Shadow.reOffsetsAndBlur = /(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function () {
+
+  'use strict';
+
+  if (fabric.StaticCanvas) {
+    fabric.warn('fabric.StaticCanvas is already defined.');
+    return;
+  }
+
+  // aliases for faster resolution
+  var extend = fabric.util.object.extend,
+      getElementOffset = fabric.util.getElementOffset,
+      removeFromArray = fabric.util.removeFromArray,
+      toFixed = fabric.util.toFixed,
+
+      CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');
+
+  /**
+   * Static canvas class
+   * @class fabric.StaticCanvas
+   * @mixes fabric.Collection
+   * @mixes fabric.Observable
+   * @see {@link http://fabricjs.com/static_canvas|StaticCanvas demo}
+   * @see {@link fabric.StaticCanvas#initialize} for constructor definition
+   * @fires before:render
+   * @fires after:render
+   * @fires canvas:cleared
+   * @fires object:added
+   * @fires object:removed
+   */
+  fabric.StaticCanvas = fabric.util.createClass(/** @lends fabric.StaticCanvas.prototype */ {
+
+    /**
+     * Constructor
+     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on
+     * @param {Object} [options] Options object
+     * @return {Object} thisArg
+     */
+    initialize: function(el, options) {
+      options || (options = { });
+
+      this._initStatic(el, options);
+    },
+
+    /**
+     * Background color of canvas instance.
+     * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}.
+     * @type {(String|fabric.Pattern)}
+     * @default
+     */
+    backgroundColor: '',
+
+    /**
+     * Background image of canvas instance.
+     * Should be set via {@link fabric.StaticCanvas#setBackgroundImage}.
+     * <b>Backwards incompatibility note:</b> The "backgroundImageOpacity"
+     * and "backgroundImageStretch" properties are deprecated since 1.3.9.
+     * Use {@link fabric.Image#opacity}, {@link fabric.Image#width} and {@link fabric.Image#height}.
+     * @type fabric.Image
+     * @default
+     */
+    backgroundImage: null,
+
+    /**
+     * Overlay color of canvas instance.
+     * Should be set via {@link fabric.StaticCanvas#setOverlayColor}
+     * @since 1.3.9
+     * @type {(String|fabric.Pattern)}
+     * @default
+     */
+    overlayColor: '',
+
+    /**
+     * Overlay image of canvas instance.
+     * Should be set via {@link fabric.StaticCanvas#setOverlayImage}.
+     * <b>Backwards incompatibility note:</b> The "overlayImageLeft"
+     * and "overlayImageTop" properties are deprecated since 1.3.9.
+     * Use {@link fabric.Image#left} and {@link fabric.Image#top}.
+     * @type fabric.Image
+     * @default
+     */
+    overlayImage: null,
+
+    /**
+     * Indicates whether toObject/toDatalessObject should include default values
+     * @type Boolean
+     * @default
+     */
+    includeDefaultValues: true,
+
+    /**
+     * Indicates whether objects' state should be saved
+     * @type Boolean
+     * @default
+     */
+    stateful: true,
+
+    /**
+     * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove} should also re-render canvas.
+     * Disabling this option could give a great performance boost when adding/removing a lot of objects to/from canvas at once
+     * (followed by a manual rendering after addition/deletion)
+     * @type Boolean
+     * @default
+     */
+    renderOnAddRemove: true,
+
+    /**
+     * Function that determines clipping of entire canvas area
+     * Being passed context as first argument. See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ}
+     * @type Function
+     * @default
+     */
+    clipTo: null,
+
+    /**
+     * Indicates whether object controls (borders/controls) are rendered above overlay image
+     * @type Boolean
+     * @default
+     */
+    controlsAboveOverlay: false,
+
+    /**
+     * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas
+     * @type Boolean
+     * @default
+     */
+    allowTouchScrolling: false,
+
+    /**
+     * Indicates whether this canvas will use image smoothing, this is on by default in browsers
+     * @type Boolean
+     * @default
+     */
+    imageSmoothingEnabled: true,
+
+    /**
+     * The transformation (in the format of Canvas transform) which focuses the viewport
+     * @type Array
+     * @default
+     */
+    viewportTransform: [1, 0, 0, 1, 0, 0],
+
+    /**
+     * if set to false background image is not affected by viewport transform
+     * @since 1.6.3
+     * @type Boolean
+     * @default
+     */
+    backgroundVpt: true,
+
+    /**
+     * if set to false overlya image is not affected by viewport transform
+     * @since 1.6.3
+     * @type Boolean
+     * @default
+     */
+    overlayVpt: true,
+
+    /**
+     * Callback; invoked right before object is about to be scaled/rotated
+     */
+    onBeforeScaleRotate: function () {
+      /* NOOP */
+    },
+
+    /**
+     * When true, canvas is scaled by devicePixelRatio for better rendering on retina screens
+     */
+    enableRetinaScaling: true,
+
+    /**
+     * @private
+     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on
+     * @param {Object} [options] Options object
+     */
+    _initStatic: function(el, options) {
+      var cb = fabric.StaticCanvas.prototype.renderAll.bind(this);
+      this._objects = [];
+      this._createLowerCanvas(el);
+      this._initOptions(options);
+      this._setImageSmoothing();
+      // only initialize retina scaling once
+      if (!this.interactive) {
+        this._initRetinaScaling();
+      }
+
+      if (options.overlayImage) {
+        this.setOverlayImage(options.overlayImage, cb);
+      }
+      if (options.backgroundImage) {
+        this.setBackgroundImage(options.backgroundImage, cb);
+      }
+      if (options.backgroundColor) {
+        this.setBackgroundColor(options.backgroundColor, cb);
+      }
+      if (options.overlayColor) {
+        this.setOverlayColor(options.overlayColor, cb);
+      }
+      this.calcOffset();
+    },
+
+    /**
+     * @private
+     */
+    _isRetinaScaling: function() {
+      return (fabric.devicePixelRatio !== 1 && this.enableRetinaScaling);
+    },
+
+    /**
+     * @private
+     * @return {Number} retinaScaling if applied, otherwise 1;
+     */
+    getRetinaScaling: function() {
+      return this._isRetinaScaling() ? fabric.devicePixelRatio : 1;
+    },
+
+    /**
+     * @private
+     */
+    _initRetinaScaling: function() {
+      if (!this._isRetinaScaling()) {
+        return;
+      }
+      this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio);
+      this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio);
+
+      this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio);
+    },
+
+    /**
+     * Calculates canvas element offset relative to the document
+     * This method is also attached as "resize" event handler of window
+     * @return {fabric.Canvas} instance
+     * @chainable
+     */
+    calcOffset: function () {
+      this._offset = getElementOffset(this.lowerCanvasEl);
+      return this;
+    },
+
+    /**
+     * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas
+     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to
+     * @param {Function} callback callback to invoke when image is loaded and set as an overlay
+     * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo}
+     * @example <caption>Normal overlayImage with left/top = 0</caption>
+     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {
+     *   // Needed to position overlayImage at 0/0
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>overlayImage with different properties</caption>
+     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {
+     *   opacity: 0.5,
+     *   angle: 45,
+     *   left: 400,
+     *   top: 400,
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>Stretched overlayImage #1 - width/height correspond to canvas width/height</caption>
+     * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img) {
+     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});
+     *    canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));
+     * });
+     * @example <caption>Stretched overlayImage #2 - width/height correspond to canvas width/height</caption>
+     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {
+     *   width: canvas.width,
+     *   height: canvas.height,
+     *   // Needed to position overlayImage at 0/0
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>overlayImage loaded from cross-origin</caption>
+     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {
+     *   opacity: 0.5,
+     *   angle: 45,
+     *   left: 400,
+     *   top: 400,
+     *   originX: 'left',
+     *   originY: 'top',
+     *   crossOrigin: 'anonymous'
+     * });
+     */
+    setOverlayImage: function (image, callback, options) {
+      return this.__setBgOverlayImage('overlayImage', image, callback, options);
+    },
+
+    /**
+     * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas
+     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to
+     * @param {Function} callback Callback to invoke when image is loaded and set as background
+     * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/YH9yD/|jsFiddle demo}
+     * @example <caption>Normal backgroundImage with left/top = 0</caption>
+     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {
+     *   // Needed to position backgroundImage at 0/0
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>backgroundImage with different properties</caption>
+     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {
+     *   opacity: 0.5,
+     *   angle: 45,
+     *   left: 400,
+     *   top: 400,
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>Stretched backgroundImage #1 - width/height correspond to canvas width/height</caption>
+     * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img) {
+     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});
+     *    canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
+     * });
+     * @example <caption>Stretched backgroundImage #2 - width/height correspond to canvas width/height</caption>
+     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {
+     *   width: canvas.width,
+     *   height: canvas.height,
+     *   // Needed to position backgroundImage at 0/0
+     *   originX: 'left',
+     *   originY: 'top'
+     * });
+     * @example <caption>backgroundImage loaded from cross-origin</caption>
+     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {
+     *   opacity: 0.5,
+     *   angle: 45,
+     *   left: 400,
+     *   top: 400,
+     *   originX: 'left',
+     *   originY: 'top',
+     *   crossOrigin: 'anonymous'
+     * });
+     */
+    setBackgroundImage: function (image, callback, options) {
+      return this.__setBgOverlayImage('backgroundImage', image, callback, options);
+    },
+
+    /**
+     * Sets {@link fabric.StaticCanvas#overlayColor|background color} for this canvas
+     * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set background color to
+     * @param {Function} callback Callback to invoke when background color is set
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo}
+     * @example <caption>Normal overlayColor - color value</caption>
+     * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));
+     * @example <caption>fabric.Pattern used as overlayColor</caption>
+     * canvas.setOverlayColor({
+     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'
+     * }, canvas.renderAll.bind(canvas));
+     * @example <caption>fabric.Pattern used as overlayColor with repeat and offset</caption>
+     * canvas.setOverlayColor({
+     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',
+     *   repeat: 'repeat',
+     *   offsetX: 200,
+     *   offsetY: 100
+     * }, canvas.renderAll.bind(canvas));
+     */
+    setOverlayColor: function(overlayColor, callback) {
+      return this.__setBgOverlayColor('overlayColor', overlayColor, callback);
+    },
+
+    /**
+     * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas
+     * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to
+     * @param {Function} callback Callback to invoke when background color is set
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo}
+     * @example <caption>Normal backgroundColor - color value</caption>
+     * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));
+     * @example <caption>fabric.Pattern used as backgroundColor</caption>
+     * canvas.setBackgroundColor({
+     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'
+     * }, canvas.renderAll.bind(canvas));
+     * @example <caption>fabric.Pattern used as backgroundColor with repeat and offset</caption>
+     * canvas.setBackgroundColor({
+     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',
+     *   repeat: 'repeat',
+     *   offsetX: 200,
+     *   offsetY: 100
+     * }, canvas.renderAll.bind(canvas));
+     */
+    setBackgroundColor: function(backgroundColor, callback) {
+      return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback);
+    },
+
+    /**
+     * @private
+     * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-imagesmoothingenabled|WhatWG Canvas Standard}
+     */
+    _setImageSmoothing: function() {
+      var ctx = this.getContext();
+
+      ctx.imageSmoothingEnabled = ctx.imageSmoothingEnabled || ctx.webkitImageSmoothingEnabled
+        || ctx.mozImageSmoothingEnabled || ctx.msImageSmoothingEnabled || ctx.oImageSmoothingEnabled;
+      ctx.imageSmoothingEnabled = this.imageSmoothingEnabled;
+    },
+
+    /**
+     * @private
+     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}
+     * or {@link fabric.StaticCanvas#overlayImage|overlayImage})
+     * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to
+     * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay
+     * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.
+     */
+    __setBgOverlayImage: function(property, image, callback, options) {
+      if (typeof image === 'string') {
+        fabric.util.loadImage(image, function(img) {
+          img && (this[property] = new fabric.Image(img, options));
+          callback && callback(img);
+        }, this, options && options.crossOrigin);
+      }
+      else {
+        options && image.setOptions(options);
+        this[property] = image;
+        callback && callback(image);
+      }
+
+      return this;
+    },
+
+    /**
+     * @private
+     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}
+     * or {@link fabric.StaticCanvas#overlayColor|overlayColor})
+     * @param {(Object|String|null)} color Object with pattern information, color value or null
+     * @param {Function} [callback] Callback is invoked when color is set
+     */
+    __setBgOverlayColor: function(property, color, callback) {
+      if (color && color.source) {
+        var _this = this;
+        fabric.util.loadImage(color.source, function(img) {
+          _this[property] = new fabric.Pattern({
+            source: img,
+            repeat: color.repeat,
+            offsetX: color.offsetX,
+            offsetY: color.offsetY
+          });
+          callback && callback();
+        });
+      }
+      else {
+        this[property] = color;
+        callback && callback();
+      }
+
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _createCanvasElement: function(canvasEl) {
+      var element = fabric.util.createCanvasElement(canvasEl)
+      if (!element.style) {
+        element.style = { };
+      }
+      if (!element) {
+        throw CANVAS_INIT_ERROR;
+      }
+      if (typeof element.getContext === 'undefined') {
+        throw CANVAS_INIT_ERROR;
+      }
+      return element;
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options object
+     */
+    _initOptions: function (options) {
+      for (var prop in options) {
+        this[prop] = options[prop];
+      }
+
+      this.width = this.width || parseInt(this.lowerCanvasEl.width, 10) || 0;
+      this.height = this.height || parseInt(this.lowerCanvasEl.height, 10) || 0;
+
+      if (!this.lowerCanvasEl.style) {
+        return;
+      }
+
+      this.lowerCanvasEl.width = this.width;
+      this.lowerCanvasEl.height = this.height;
+
+      this.lowerCanvasEl.style.width = this.width + 'px';
+      this.lowerCanvasEl.style.height = this.height + 'px';
+
+      this.viewportTransform = this.viewportTransform.slice();
+    },
+
+    /**
+     * Creates a bottom canvas
+     * @private
+     * @param {HTMLElement} [canvasEl]
+     */
+    _createLowerCanvas: function (canvasEl) {
+      this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(canvasEl);
+
+      fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');
+
+      if (this.interactive) {
+        this._applyCanvasStyle(this.lowerCanvasEl);
+      }
+
+      this.contextContainer = this.lowerCanvasEl.getContext('2d');
+    },
+
+    /**
+     * Returns canvas width (in px)
+     * @return {Number}
+     */
+    getWidth: function () {
+      return this.width;
+    },
+
+    /**
+     * Returns canvas height (in px)
+     * @return {Number}
+     */
+    getHeight: function () {
+      return this.height;
+    },
+
+    /**
+     * Sets width of this canvas instance
+     * @param {Number|String} value                         Value to set width to
+     * @param {Object}        [options]                     Options object
+     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions
+     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    setWidth: function (value, options) {
+      return this.setDimensions({ width: value }, options);
+    },
+
+    /**
+     * Sets height of this canvas instance
+     * @param {Number|String} value                         Value to set height to
+     * @param {Object}        [options]                     Options object
+     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions
+     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    setHeight: function (value, options) {
+      return this.setDimensions({ height: value }, options);
+    },
+
+    /**
+     * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)
+     * @param {Object}        dimensions                    Object with width/height properties
+     * @param {Number|String} [dimensions.width]            Width of canvas element
+     * @param {Number|String} [dimensions.height]           Height of canvas element
+     * @param {Object}        [options]                     Options object
+     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions
+     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    setDimensions: function (dimensions, options) {
+      var cssValue;
+
+      options = options || {};
+
+      for (var prop in dimensions) {
+        cssValue = dimensions[prop];
+
+        if (!options.cssOnly) {
+          this._setBackstoreDimension(prop, dimensions[prop]);
+          cssValue += 'px';
+        }
+
+        if (!options.backstoreOnly) {
+          this._setCssDimension(prop, cssValue);
+        }
+      }
+      this._initRetinaScaling();
+      this._setImageSmoothing();
+      this.calcOffset();
+
+      if (!options.cssOnly) {
+        this.renderAll();
+      }
+
+      return this;
+    },
+
+    /**
+     * Helper for setting width/height
+     * @private
+     * @param {String} prop property (width|height)
+     * @param {Number} value value to set property to
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    _setBackstoreDimension: function (prop, value) {
+      this.lowerCanvasEl[prop] = value;
+
+      if (this.upperCanvasEl) {
+        this.upperCanvasEl[prop] = value;
+      }
+
+      if (this.cacheCanvasEl) {
+        this.cacheCanvasEl[prop] = value;
+      }
+
+      this[prop] = value;
+
+      return this;
+    },
+
+    /**
+     * Helper for setting css width/height
+     * @private
+     * @param {String} prop property (width|height)
+     * @param {String} value value to set property to
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    _setCssDimension: function (prop, value) {
+      this.lowerCanvasEl.style[prop] = value;
+
+      if (this.upperCanvasEl) {
+        this.upperCanvasEl.style[prop] = value;
+      }
+
+      if (this.wrapperEl) {
+        this.wrapperEl.style[prop] = value;
+      }
+
+      return this;
+    },
+
+    /**
+     * Returns canvas zoom level
+     * @return {Number}
+     */
+    getZoom: function () {
+      return Math.sqrt(this.viewportTransform[0] * this.viewportTransform[3]);
+    },
+
+    /**
+     * Sets viewport transform of this canvas instance
+     * @param {Array} vpt the transform in the form of context.transform
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    setViewportTransform: function (vpt) {
+      var activeGroup = this._activeGroup, object;
+      this.viewportTransform = vpt;
+      for (var i = 0, len = this._objects.length; i < len; i++) {
+        object = this._objects[i];
+        object.group || object.setCoords();
+      }
+      if (activeGroup) {
+        activeGroup.setCoords();
+      }
+      this.renderAll();
+      return this;
+    },
+
+    /**
+     * Sets zoom level of this canvas instance, zoom centered around point
+     * @param {fabric.Point} point to zoom with respect to
+     * @param {Number} value to set zoom to, less than 1 zooms out
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    zoomToPoint: function (point, value) {
+      // TODO: just change the scale, preserve other transformations
+      var before = point, vpt = this.viewportTransform.slice(0);
+      point = fabric.util.transformPoint(point, fabric.util.invertTransform(this.viewportTransform));
+      vpt[0] = value;
+      vpt[3] = value;
+      var after = fabric.util.transformPoint(point, vpt);
+      vpt[4] += before.x - after.x;
+      vpt[5] += before.y - after.y;
+      return this.setViewportTransform(vpt);
+    },
+
+    /**
+     * Sets zoom level of this canvas instance
+     * @param {Number} value to set zoom to, less than 1 zooms out
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    setZoom: function (value) {
+      this.zoomToPoint(new fabric.Point(0, 0), value);
+      return this;
+    },
+
+    /**
+     * Pan viewport so as to place point at top left corner of canvas
+     * @param {fabric.Point} point to move to
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    absolutePan: function (point) {
+      var vpt = this.viewportTransform.slice(0);
+      vpt[4] = -point.x;
+      vpt[5] = -point.y;
+      return this.setViewportTransform(vpt);
+    },
+
+    /**
+     * Pans viewpoint relatively
+     * @param {fabric.Point} point (position vector) to move by
+     * @return {fabric.Canvas} instance
+     * @chainable true
+     */
+    relativePan: function (point) {
+      return this.absolutePan(new fabric.Point(
+        -point.x - this.viewportTransform[4],
+        -point.y - this.viewportTransform[5]
+      ));
+    },
+
+    /**
+     * Returns &lt;canvas> element corresponding to this instance
+     * @return {HTMLCanvasElement}
+     */
+    getElement: function () {
+      return this.lowerCanvasEl;
+    },
+
+    /**
+     * @private
+     * @param {fabric.Object} obj Object that was added
+     */
+    _onObjectAdded: function(obj) {
+      this.stateful && obj.setupState();
+      obj._set('canvas', this);
+      obj.setCoords();
+      this.fire('object:added', { target: obj });
+      obj.fire('added');
+    },
+
+    /**
+     * @private
+     * @param {fabric.Object} obj Object that was removed
+     */
+    _onObjectRemoved: function(obj) {
+      this.fire('object:removed', { target: obj });
+      obj.fire('removed');
+      delete obj.canvas;
+    },
+
+    /**
+     * Clears specified context of canvas element
+     * @param {CanvasRenderingContext2D} ctx Context to clear
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    clearContext: function(ctx) {
+      ctx.clearRect(0, 0, this.width, this.height);
+      return this;
+    },
+
+    /**
+     * Returns context of canvas where objects are drawn
+     * @return {CanvasRenderingContext2D}
+     */
+    getContext: function () {
+      return this.contextContainer;
+    },
+
+    /**
+     * Clears all contexts (background, main, top) of an instance
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    clear: function () {
+      this._objects.length = 0;
+      this.backgroundImage = null;
+      this.overlayImage = null;
+      this.backgroundColor = '';
+      this.overlayColor = ''
+      if (this._hasITextHandlers) {
+        this.off('selection:cleared', this._canvasITextSelectionClearedHanlder);
+        this.off('object:selected', this._canvasITextSelectionClearedHanlder);
+        this.off('mouse:up', this._mouseUpITextHandler);
+        this._iTextInstances = null;
+        this._hasITextHandlers = false;
+      }
+      this.clearContext(this.contextContainer);
+      this.fire('canvas:cleared');
+      this.renderAll();
+      return this;
+    },
+
+    /**
+     * Renders both the canvas.
+     * @return {fabric.Canvas} instance
+     * @chainable
+     */
+    renderAll: function () {
+      var canvasToDrawOn = this.contextContainer;
+      this.renderCanvas(canvasToDrawOn, this._objects);
+      return this;
+    },
+
+    /**
+     * Renders background, objects, overlay and controls.
+     * @param {CanvasRenderingContext2D} ctx
+     * @param {Array} objects to render
+     * @return {fabric.Canvas} instance
+     * @chainable
+     */
+    renderCanvas: function(ctx, objects) {
+      this.clearContext(ctx);
+      this.fire('before:render');
+      if (this.clipTo) {
+        fabric.util.clipContext(this, ctx);
+      }
+      this._renderBackground(ctx);
+
+      ctx.save();
+      //apply viewport transform once for all rendering process
+      ctx.transform.apply(ctx, this.viewportTransform);
+      this._renderObjects(ctx, objects);
+      ctx.restore();
+      if (!this.controlsAboveOverlay && this.interactive) {
+        this.drawControls(ctx);
+      }
+      if (this.clipTo) {
+        ctx.restore();
+      }
+      this._renderOverlay(ctx);
+      if (this.controlsAboveOverlay && this.interactive) {
+        this.drawControls(ctx);
+      }
+      this.fire('after:render');
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Array} objects to render
+     */
+    _renderObjects: function(ctx, objects) {
+      for (var i = 0, length = objects.length; i < length; ++i) {
+        objects[i] && objects[i].render(ctx);
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {string} property 'background' or 'overlay'
+     */
+    _renderBackgroundOrOverlay: function(ctx, property) {
+      var object = this[property + 'Color'];
+      if (object) {
+        ctx.fillStyle = object.toLive
+          ? object.toLive(ctx)
+          : object;
+
+        ctx.fillRect(
+          object.offsetX || 0,
+          object.offsetY || 0,
+          this.width,
+          this.height);
+      }
+      object = this[property + 'Image'];
+      if (object) {
+        if (this[property + 'Vpt']) {
+          ctx.save();
+          ctx.transform.apply(ctx, this.viewportTransform);
+        }
+        object.render(ctx);
+        this[property + 'Vpt'] && ctx.restore();
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderBackground: function(ctx) {
+      this._renderBackgroundOrOverlay(ctx, 'background');
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderOverlay: function(ctx) {
+      this._renderBackgroundOrOverlay(ctx, 'overlay');
+    },
+
+    /**
+     * Returns coordinates of a center of canvas.
+     * Returned value is an object with top and left properties
+     * @return {Object} object with "top" and "left" number values
+     */
+    getCenter: function () {
+      return {
+        top: this.getHeight() / 2,
+        left: this.getWidth() / 2
+      };
+    },
+
+    /**
+     * Centers object horizontally in the canvas
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center horizontally
+     * @return {fabric.Canvas} thisArg
+     */
+    centerObjectH: function (object) {
+      return this._centerObject(object, new fabric.Point(this.getCenter().left, object.getCenterPoint().y));
+    },
+
+    /**
+     * Centers object vertically in the canvas
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center vertically
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    centerObjectV: function (object) {
+      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenter().top));
+    },
+
+    /**
+     * Centers object vertically and horizontally in the canvas
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center vertically and horizontally
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    centerObject: function(object) {
+      var center = this.getCenter();
+
+      return this._centerObject(object, new fabric.Point(center.left, center.top));
+    },
+
+    /**
+     * Centers object vertically and horizontally in the viewport
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center vertically and horizontally
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    viewportCenterObject: function(object) {
+      var vpCenter = this.getVpCenter();
+
+      return this._centerObject(object, vpCenter);
+    },
+
+    /**
+     * Centers object horizontally in the viewport, object.top is unchanged
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center vertically and horizontally
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    viewportCenterObjectH: function(object) {
+      var vpCenter = this.getVpCenter();
+      this._centerObject(object, new fabric.Point(vpCenter.x, object.getCenterPoint().y));
+      return this;
+    },
+
+    /**
+     * Centers object Vertically in the viewport, object.top is unchanged
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @param {fabric.Object} object Object to center vertically and horizontally
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    viewportCenterObjectV: function(object) {
+      var vpCenter = this.getVpCenter();
+
+      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, vpCenter.y));
+    },
+
+    /**
+     * Calculate the point in canvas that correspond to the center of actual viewport.
+     * @return {fabric.Point} vpCenter, viewport center
+     * @chainable
+     */
+    getVpCenter: function() {
+      var center = this.getCenter(),
+          iVpt = fabric.util.invertTransform(this.viewportTransform);
+      return fabric.util.transformPoint({ x: center.left, y: center.top }, iVpt);
+    },
+
+    /**
+     * @private
+     * @param {fabric.Object} object Object to center
+     * @param {fabric.Point} center Center point
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    _centerObject: function(object, center) {
+      object.setPositionByOrigin(center, 'center', 'center');
+      this.renderAll();
+      return this;
+    },
+
+    /**
+     * Returs dataless JSON representation of canvas
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {String} json string
+     */
+    toDatalessJSON: function (propertiesToInclude) {
+      return this.toDatalessObject(propertiesToInclude);
+    },
+
+    /**
+     * Returns object representation of canvas
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function (propertiesToInclude) {
+      return this._toObjectMethod('toObject', propertiesToInclude);
+    },
+
+    /**
+     * Returns dataless object representation of canvas
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toDatalessObject: function (propertiesToInclude) {
+      return this._toObjectMethod('toDatalessObject', propertiesToInclude);
+    },
+
+    /**
+     * @private
+     */
+    _toObjectMethod: function (methodName, propertiesToInclude) {
+
+      var data = {
+        objects: this._toObjects(methodName, propertiesToInclude)
+      };
+
+      extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));
+
+      fabric.util.populateWithProperties(this, data, propertiesToInclude);
+
+      return data;
+    },
+
+    /**
+     * @private
+     */
+    _toObjects: function(methodName, propertiesToInclude) {
+      return this.getObjects().filter(function(object) {
+        return !object.excludeFromExport;
+      }).map(function(instance) {
+        return this._toObject(instance, methodName, propertiesToInclude);
+      }, this);
+    },
+
+    /**
+     * @private
+     */
+    _toObject: function(instance, methodName, propertiesToInclude) {
+      var originalValue;
+
+      if (!this.includeDefaultValues) {
+        originalValue = instance.includeDefaultValues;
+        instance.includeDefaultValues = false;
+      }
+
+      var object = instance[methodName](propertiesToInclude);
+      if (!this.includeDefaultValues) {
+        instance.includeDefaultValues = originalValue;
+      }
+      return object;
+    },
+
+    /**
+     * @private
+     */
+    __serializeBgOverlay: function(methodName, propertiesToInclude) {
+      var data = {
+        background: (this.backgroundColor && this.backgroundColor.toObject)
+          ? this.backgroundColor.toObject(propertiesToInclude)
+          : this.backgroundColor
+      };
+
+      if (this.overlayColor) {
+        data.overlay = this.overlayColor.toObject
+          ? this.overlayColor.toObject(propertiesToInclude)
+          : this.overlayColor;
+      }
+      if (this.backgroundImage) {
+        data.backgroundImage = this._toObject(this.backgroundImage, methodName, propertiesToInclude);
+      }
+      if (this.overlayImage) {
+        data.overlayImage = this._toObject(this.overlayImage, methodName, propertiesToInclude);
+      }
+
+      return data;
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,
+     * a zoomed canvas will then produce zoomed SVG output.
+     * @type Boolean
+     * @default
+     */
+    svgViewportTransformation: true,
+
+    /**
+     * Returns SVG representation of canvas
+     * @function
+     * @param {Object} [options] Options object for SVG output
+     * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included
+     * @param {Object} [options.viewBox] SVG viewbox object
+     * @param {Number} [options.viewBox.x] x-cooridnate of viewbox
+     * @param {Number} [options.viewBox.y] y-coordinate of viewbox
+     * @param {Number} [options.viewBox.width] Width of viewbox
+     * @param {Number} [options.viewBox.height] Height of viewbox
+     * @param {String} [options.encoding=UTF-8] Encoding of SVG output
+     * @param {String} [options.width] desired width of svg with or without units
+     * @param {String} [options.height] desired height of svg with or without units
+     * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.
+     * @return {String} SVG string
+     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}
+     * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo}
+     * @example <caption>Normal SVG output</caption>
+     * var svg = canvas.toSVG();
+     * @example <caption>SVG output without preamble (without &lt;?xml ../>)</caption>
+     * var svg = canvas.toSVG({suppressPreamble: true});
+     * @example <caption>SVG output with viewBox attribute</caption>
+     * var svg = canvas.toSVG({
+     *   viewBox: {
+     *     x: 100,
+     *     y: 100,
+     *     width: 200,
+     *     height: 300
+     *   }
+     * });
+     * @example <caption>SVG output with different encoding (default: UTF-8)</caption>
+     * var svg = canvas.toSVG({encoding: 'ISO-8859-1'});
+     * @example <caption>Modify SVG output with reviver function</caption>
+     * var svg = canvas.toSVG(null, function(svg) {
+     *   return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', '');
+     * });
+     */
+    toSVG: function(options, reviver) {
+      options || (options = { });
+
+      var markup = [];
+
+      this._setSVGPreamble(markup, options);
+      this._setSVGHeader(markup, options);
+
+      this._setSVGBgOverlayColor(markup, 'backgroundColor');
+      this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);
+
+      this._setSVGObjects(markup, reviver);
+
+      this._setSVGBgOverlayColor(markup, 'overlayColor');
+      this._setSVGBgOverlayImage(markup, 'overlayImage', reviver);
+
+      markup.push('</svg>');
+
+      return markup.join('');
+    },
+
+    /**
+     * @private
+     */
+    _setSVGPreamble: function(markup, options) {
+      if (options.suppressPreamble) {
+        return;
+      }
+      markup.push(
+        '<?xml version="1.0" encoding="', (options.encoding || 'UTF-8'), '" standalone="no" ?>\n',
+          '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ',
+            '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
+      );
+    },
+
+    /**
+     * @private
+     */
+    _setSVGHeader: function(markup, options) {
+      var width = options.width || this.width,
+          height = options.height || this.height,
+          vpt, viewBox = 'viewBox="0 0 ' + this.width + ' ' + this.height + '" ',
+          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
+
+      if (options.viewBox) {
+        viewBox = 'viewBox="' +
+                options.viewBox.x + ' ' +
+                options.viewBox.y + ' ' +
+                options.viewBox.width + ' ' +
+                options.viewBox.height + '" ';
+      }
+      else {
+        if (this.svgViewportTransformation) {
+          vpt = this.viewportTransform;
+          viewBox = 'viewBox="' +
+                  toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' +
+                  toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' +
+                  toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' +
+                  toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '" ';
+        }
+      }
+
+      markup.push(
+        '<svg ',
+          'xmlns="http://www.w3.org/2000/svg" ',
+          'xmlns:xlink="http://www.w3.org/1999/xlink" ',
+          'version="1.1" ',
+          'width="', width, '" ',
+          'height="', height, '" ',
+          (this.backgroundColor && !this.backgroundColor.toLive
+            ? 'style="background-color: ' + this.backgroundColor + '" '
+            : null),
+          viewBox,
+          'xml:space="preserve">\n',
+        '<desc>Created with Fabric.js ', fabric.version, '</desc>\n',
+        '<defs>',
+          fabric.createSVGFontFacesMarkup(this.getObjects()),
+          fabric.createSVGRefElementsMarkup(this),
+        '</defs>\n'
+      );
+    },
+
+    /**
+     * @private
+     */
+    _setSVGObjects: function(markup, reviver) {
+      var instance;
+      for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) {
+        instance = objects[i];
+        if (instance.excludeFromExport) {
+          continue;
+        }
+        this._setSVGObject(markup, instance, reviver);
+      }
+    },
+
+    /**
+     * push single object svg representation in the markup
+     * @private
+     */
+    _setSVGObject: function(markup, instance, reviver) {
+      markup.push(instance.toSVG(reviver));
+    },
+
+    /**
+     * @private
+     */
+    _setSVGBgOverlayImage: function(markup, property, reviver) {
+      if (this[property] && this[property].toSVG) {
+        markup.push(this[property].toSVG(reviver));
+      }
+    },
+
+    /**
+     * @private
+     */
+    _setSVGBgOverlayColor: function(markup, property) {
+      if (this[property] && this[property].source) {
+        markup.push(
+          '<rect x="', this[property].offsetX, '" y="', this[property].offsetY, '" ',
+            'width="',
+              (this[property].repeat === 'repeat-y' || this[property].repeat === 'no-repeat'
+                ? this[property].source.width
+                : this.width),
+            '" height="',
+              (this[property].repeat === 'repeat-x' || this[property].repeat === 'no-repeat'
+                ? this[property].source.height
+                : this.height),
+            '" fill="url(#' + property + 'Pattern)"',
+          '></rect>\n'
+        );
+      }
+      else if (this[property] && property === 'overlayColor') {
+        markup.push(
+          '<rect x="0" y="0" ',
+            'width="', this.width,
+            '" height="', this.height,
+            '" fill="', this[property], '"',
+          '></rect>\n'
+        );
+      }
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Moves an object or the objects of a multiple selection
+     * to the bottom of the stack of drawn objects
+     * @param {fabric.Object} object Object to send to back
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    sendToBack: function (object) {
+      if (!object) {
+        return this;
+      }
+      var activeGroup = this._activeGroup,
+          i, obj, objs;
+      if (object === activeGroup) {
+        objs = activeGroup._objects;
+        for (i = objs.length; i--;) {
+          obj = objs[i];
+          removeFromArray(this._objects, obj);
+          this._objects.unshift(obj);
+        }
+      }
+      else {
+        removeFromArray(this._objects, object);
+        this._objects.unshift(object);
+      }
+      return this.renderAll && this.renderAll();
+    },
+
+    /**
+     * Moves an object or the objects of a multiple selection
+     * to the top of the stack of drawn objects
+     * @param {fabric.Object} object Object to send
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    bringToFront: function (object) {
+      if (!object) {
+        return this;
+      }
+      var activeGroup = this._activeGroup,
+          i, obj, objs;
+      if (object === activeGroup) {
+        objs = activeGroup._objects;
+        for (i = 0; i < objs.length; i++) {
+          obj = objs[i];
+          removeFromArray(this._objects, obj);
+          this._objects.push(obj);
+        }
+      }
+      else {
+        removeFromArray(this._objects, object);
+        this._objects.push(object);
+      }
+      return this.renderAll && this.renderAll();
+    },
+
+    /**
+     * Moves an object or a selection down in stack of drawn objects
+     * @param {fabric.Object} object Object to send
+     * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    sendBackwards: function (object, intersecting) {
+      if (!object) {
+        return this;
+      }
+      var activeGroup = this._activeGroup,
+          i, obj, idx, newIdx, objs;
+
+      if (object === activeGroup) {
+        objs = activeGroup._objects;
+        for (i = 0; i < objs.length; i++) {
+          obj = objs[i];
+          idx = this._objects.indexOf(obj);
+          if (idx !== 0) {
+            newIdx = idx - 1;
+            removeFromArray(this._objects, obj);
+            this._objects.splice(newIdx, 0, obj);
+          }
+        }
+      }
+      else {
+        idx = this._objects.indexOf(object);
+        if (idx !== 0) {
+          // if object is not on the bottom of stack
+          newIdx = this._findNewLowerIndex(object, idx, intersecting);
+          removeFromArray(this._objects, object);
+          this._objects.splice(newIdx, 0, object);
+        }
+      }
+      this.renderAll && this.renderAll();
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _findNewLowerIndex: function(object, idx, intersecting) {
+      var newIdx;
+
+      if (intersecting) {
+        newIdx = idx;
+
+        // traverse down the stack looking for the nearest intersecting object
+        for (var i = idx - 1; i >= 0; --i) {
+
+          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||
+                               object.isContainedWithinObject(this._objects[i]) ||
+                               this._objects[i].isContainedWithinObject(object);
+
+          if (isIntersecting) {
+            newIdx = i;
+            break;
+          }
+        }
+      }
+      else {
+        newIdx = idx - 1;
+      }
+
+      return newIdx;
+    },
+
+    /**
+     * Moves an object or a selection up in stack of drawn objects
+     * @param {fabric.Object} object Object to send
+     * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    bringForward: function (object, intersecting) {
+      if (!object) {
+        return this;
+      }
+      var activeGroup = this._activeGroup,
+          i, obj, idx, newIdx, objs;
+
+      if (object === activeGroup) {
+        objs = activeGroup._objects;
+        for (i = objs.length; i--;) {
+          obj = objs[i];
+          idx = this._objects.indexOf(obj);
+          if (idx !== this._objects.length - 1) {
+            newIdx = idx + 1;
+            removeFromArray(this._objects, obj);
+            this._objects.splice(newIdx, 0, obj);
+          }
+        }
+      }
+      else {
+        idx = this._objects.indexOf(object);
+        if (idx !== this._objects.length - 1) {
+          // if object is not on top of stack (last item in an array)
+          newIdx = this._findNewUpperIndex(object, idx, intersecting);
+          removeFromArray(this._objects, object);
+          this._objects.splice(newIdx, 0, object);
+        }
+      }
+      this.renderAll && this.renderAll();
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _findNewUpperIndex: function(object, idx, intersecting) {
+      var newIdx;
+
+      if (intersecting) {
+        newIdx = idx;
+
+        // traverse up the stack looking for the nearest intersecting object
+        for (var i = idx + 1; i < this._objects.length; ++i) {
+
+          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||
+                               object.isContainedWithinObject(this._objects[i]) ||
+                               this._objects[i].isContainedWithinObject(object);
+
+          if (isIntersecting) {
+            newIdx = i;
+            break;
+          }
+        }
+      }
+      else {
+        newIdx = idx + 1;
+      }
+
+      return newIdx;
+    },
+
+    /**
+     * Moves an object to specified level in stack of drawn objects
+     * @param {fabric.Object} object Object to send
+     * @param {Number} index Position to move to
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    moveTo: function (object, index) {
+      removeFromArray(this._objects, object);
+      this._objects.splice(index, 0, object);
+      return this.renderAll && this.renderAll();
+    },
+
+    /**
+     * Clears a canvas element and removes all event listeners
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    dispose: function () {
+      this.clear();
+      return this;
+    },
+
+    /**
+     * Returns a string representation of an instance
+     * @return {String} string representation of an instance
+     */
+    toString: function () {
+      return '#<fabric.Canvas (' + this.complexity() + '): ' +
+               '{ objects: ' + this.getObjects().length + ' }>';
+    }
+  });
+
+  extend(fabric.StaticCanvas.prototype, fabric.Observable);
+  extend(fabric.StaticCanvas.prototype, fabric.Collection);
+  extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);
+
+  extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ {
+
+    /**
+     * @static
+     * @type String
+     * @default
+     */
+    EMPTY_JSON: '{"objects": [], "background": "white"}',
+
+    /**
+     * Provides a way to check support of some of the canvas methods
+     * (either those of HTMLCanvasElement itself, or rendering context)
+     *
+     * @param {String} methodName Method to check support for;
+     *                            Could be one of "getImageData", "toDataURL", "toDataURLWithQuality" or "setLineDash"
+     * @return {Boolean | null} `true` if method is supported (or at least exists),
+     *                          `null` if canvas element or context can not be initialized
+     */
+    supports: function (methodName) {
+      var el = fabric.util.createCanvasElement();
+
+      if (!el || !el.getContext) {
+        return null;
+      }
+
+      var ctx = el.getContext('2d');
+      if (!ctx) {
+        return null;
+      }
+
+      switch (methodName) {
+
+        case 'getImageData':
+          return typeof ctx.getImageData !== 'undefined';
+
+        case 'setLineDash':
+          return typeof ctx.setLineDash !== 'undefined';
+
+        case 'toDataURL':
+          return typeof el.toDataURL !== 'undefined';
+
+        case 'toDataURLWithQuality':
+          try {
+            el.toDataURL('image/jpeg', 0);
+            return true;
+          }
+          catch (e) { }
+          return false;
+
+        default:
+          return null;
+      }
+    }
+  });
+
+  /**
+   * Returns JSON representation of canvas
+   * @function
+   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+   * @return {String} JSON string
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}
+   * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo}
+   * @example <caption>JSON without additional properties</caption>
+   * var json = canvas.toJSON();
+   * @example <caption>JSON with additional properties included</caption>
+   * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY', 'lockUniScaling']);
+   * @example <caption>JSON without default values</caption>
+   * canvas.includeDefaultValues = false;
+   * var json = canvas.toJSON();
+   */
+  fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject;
+
+})();
+
+
+/**
+ * BaseBrush class
+ * @class fabric.BaseBrush
+ * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo}
+ */
+fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ {
+
+  /**
+   * Color of a brush
+   * @type String
+   * @default
+   */
+  color: 'rgb(0, 0, 0)',
+
+  /**
+   * Width of a brush
+   * @type Number
+   * @default
+   */
+  width: 1,
+
+  /**
+   * Shadow object representing shadow of this shape.
+   * <b>Backwards incompatibility note:</b> This property replaces "shadowColor" (String), "shadowOffsetX" (Number),
+   * "shadowOffsetY" (Number) and "shadowBlur" (Number) since v1.2.12
+   * @type fabric.Shadow
+   * @default
+   */
+  shadow: null,
+
+  /**
+   * Line endings style of a brush (one of "butt", "round", "square")
+   * @type String
+   * @default
+   */
+  strokeLineCap: 'round',
+
+  /**
+   * Corner style of a brush (one of "bevil", "round", "miter")
+   * @type String
+   * @default
+   */
+  strokeLineJoin: 'round',
+
+  /**
+   * Stroke Dash Array.
+   * @type Array
+   * @default
+   */
+  strokeDashArray: null,
+
+  /**
+   * Sets shadow of an object
+   * @param {Object|String} [options] Options object or string (e.g. "2px 2px 10px rgba(0,0,0,0.2)")
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  setShadow: function(options) {
+    this.shadow = new fabric.Shadow(options);
+    return this;
+  },
+
+  /**
+   * Sets brush styles
+   * @private
+   */
+  _setBrushStyles: function() {
+    var ctx = this.canvas.contextTop;
+
+    ctx.strokeStyle = this.color;
+    ctx.lineWidth = this.width;
+    ctx.lineCap = this.strokeLineCap;
+    ctx.lineJoin = this.strokeLineJoin;
+    if (this.strokeDashArray && fabric.StaticCanvas.supports('setLineDash')) {
+      ctx.setLineDash(this.strokeDashArray);
+    }
+  },
+
+  /**
+   * Sets brush shadow styles
+   * @private
+   */
+  _setShadow: function() {
+    if (!this.shadow) {
+      return;
+    }
+
+    var ctx = this.canvas.contextTop;
+
+    ctx.shadowColor = this.shadow.color;
+    ctx.shadowBlur = this.shadow.blur;
+    ctx.shadowOffsetX = this.shadow.offsetX;
+    ctx.shadowOffsetY = this.shadow.offsetY;
+  },
+
+  /**
+   * Removes brush shadow styles
+   * @private
+   */
+  _resetShadow: function() {
+    var ctx = this.canvas.contextTop;
+
+    ctx.shadowColor = '';
+    ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
+  }
+});
+
+
+(function() {
+
+  /**
+   * PencilBrush class
+   * @class fabric.PencilBrush
+   * @extends fabric.BaseBrush
+   */
+  fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {
+
+    /**
+     * Constructor
+     * @param {fabric.Canvas} canvas
+     * @return {fabric.PencilBrush} Instance of a pencil brush
+     */
+    initialize: function(canvas) {
+      this.canvas = canvas;
+      this._points = [];
+    },
+
+    /**
+     * Inovoked on mouse down
+     * @param {Object} pointer
+     */
+    onMouseDown: function(pointer) {
+      this._prepareForDrawing(pointer);
+      // capture coordinates immediately
+      // this allows to draw dots (when movement never occurs)
+      this._captureDrawingPath(pointer);
+      this._render();
+    },
+
+    /**
+     * Inovoked on mouse move
+     * @param {Object} pointer
+     */
+    onMouseMove: function(pointer) {
+      this._captureDrawingPath(pointer);
+      // redraw curve
+      // clear top canvas
+      this.canvas.clearContext(this.canvas.contextTop);
+      this._render();
+    },
+
+    /**
+     * Invoked on mouse up
+     */
+    onMouseUp: function() {
+      this._finalizeAndAddPath();
+    },
+
+    /**
+     * @private
+     * @param {Object} pointer Actual mouse position related to the canvas.
+     */
+    _prepareForDrawing: function(pointer) {
+
+      var p = new fabric.Point(pointer.x, pointer.y);
+
+      this._reset();
+      this._addPoint(p);
+
+      this.canvas.contextTop.moveTo(p.x, p.y);
+    },
+
+    /**
+     * @private
+     * @param {fabric.Point} point Point to be added to points array
+     */
+    _addPoint: function(point) {
+      this._points.push(point);
+    },
+
+    /**
+     * Clear points array and set contextTop canvas style.
+     * @private
+     */
+    _reset: function() {
+      this._points.length = 0;
+
+      this._setBrushStyles();
+      this._setShadow();
+    },
+
+    /**
+     * @private
+     * @param {Object} pointer Actual mouse position related to the canvas.
+     */
+    _captureDrawingPath: function(pointer) {
+      var pointerPoint = new fabric.Point(pointer.x, pointer.y);
+      this._addPoint(pointerPoint);
+    },
+
+    /**
+     * Draw a smooth path on the topCanvas using quadraticCurveTo
+     * @private
+     */
+    _render: function() {
+      var ctx  = this.canvas.contextTop,
+          v = this.canvas.viewportTransform,
+          p1 = this._points[0],
+          p2 = this._points[1];
+
+      ctx.save();
+      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
+      ctx.beginPath();
+
+      //if we only have 2 points in the path and they are the same
+      //it means that the user only clicked the canvas without moving the mouse
+      //then we should be drawing a dot. A path isn't drawn between two identical dots
+      //that's why we set them apart a bit
+      if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {
+        p1.x -= 0.5;
+        p2.x += 0.5;
+      }
+      ctx.moveTo(p1.x, p1.y);
+
+      for (var i = 1, len = this._points.length; i < len; i++) {
+        // we pick the point between pi + 1 & pi + 2 as the
+        // end point and p1 as our control point.
+        var midPoint = p1.midPointFrom(p2);
+        ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
+
+        p1 = this._points[i];
+        p2 = this._points[i + 1];
+      }
+      // Draw last line as a straight line while
+      // we wait for the next point to be able to calculate
+      // the bezier control point
+      ctx.lineTo(p1.x, p1.y);
+      ctx.stroke();
+      ctx.restore();
+    },
+
+    /**
+     * Converts points to SVG path
+     * @param {Array} points Array of points
+     * @return {String} SVG path
+     */
+    convertPointsToSVGPath: function(points) {
+      var path = [],
+          p1 = new fabric.Point(points[0].x, points[0].y),
+          p2 = new fabric.Point(points[1].x, points[1].y);
+
+      path.push('M ', points[0].x, ' ', points[0].y, ' ');
+      for (var i = 1, len = points.length; i < len; i++) {
+        var midPoint = p1.midPointFrom(p2);
+        // p1 is our bezier control point
+        // midpoint is our endpoint
+        // start point is p(i-1) value.
+        path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' ');
+        p1 = new fabric.Point(points[i].x, points[i].y);
+        if ((i + 1) < points.length) {
+          p2 = new fabric.Point(points[i + 1].x, points[i + 1].y);
+        }
+      }
+      path.push('L ', p1.x, ' ', p1.y, ' ');
+      return path;
+    },
+
+    /**
+     * Creates fabric.Path object to add on canvas
+     * @param {String} pathData Path data
+     * @return {fabric.Path} Path to add on canvas
+     */
+    createPath: function(pathData) {
+      var path = new fabric.Path(pathData, {
+        fill: null,
+        stroke: this.color,
+        strokeWidth: this.width,
+        strokeLineCap: this.strokeLineCap,
+        strokeLineJoin: this.strokeLineJoin,
+        strokeDashArray: this.strokeDashArray,
+        originX: 'center',
+        originY: 'center'
+      });
+
+      if (this.shadow) {
+        this.shadow.affectStroke = true;
+        path.setShadow(this.shadow);
+      }
+
+      return path;
+    },
+
+    /**
+     * On mouseup after drawing the path on contextTop canvas
+     * we use the points captured to create an new fabric path object
+     * and add it to the fabric canvas.
+     */
+    _finalizeAndAddPath: function() {
+      var ctx = this.canvas.contextTop;
+      ctx.closePath();
+
+      var pathData = this.convertPointsToSVGPath(this._points).join('');
+      if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {
+        // do not create 0 width/height paths, as they are
+        // rendered inconsistently across browsers
+        // Firefox 4, for example, renders a dot,
+        // whereas Chrome 10 renders nothing
+        this.canvas.renderAll();
+        return;
+      }
+
+      var path = this.createPath(pathData);
+
+      this.canvas.add(path);
+      path.setCoords();
+
+      this.canvas.clearContext(this.canvas.contextTop);
+      this._resetShadow();
+      this.canvas.renderAll();
+
+      // fire event 'path' created
+      this.canvas.fire('path:created', { path: path });
+    }
+  });
+})();
+
+
+/**
+ * CircleBrush class
+ * @class fabric.CircleBrush
+ */
+fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ {
+
+  /**
+   * Width of a brush
+   * @type Number
+   * @default
+   */
+  width: 10,
+
+  /**
+   * Constructor
+   * @param {fabric.Canvas} canvas
+   * @return {fabric.CircleBrush} Instance of a circle brush
+   */
+  initialize: function(canvas) {
+    this.canvas = canvas;
+    this.points = [];
+  },
+
+  /**
+   * Invoked inside on mouse down and mouse move
+   * @param {Object} pointer
+   */
+  drawDot: function(pointer) {
+    var point = this.addPoint(pointer),
+        ctx = this.canvas.contextTop,
+        v = this.canvas.viewportTransform;
+    ctx.save();
+    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
+
+    ctx.fillStyle = point.fill;
+    ctx.beginPath();
+    ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
+    ctx.closePath();
+    ctx.fill();
+
+    ctx.restore();
+  },
+
+  /**
+   * Invoked on mouse down
+   */
+  onMouseDown: function(pointer) {
+    this.points.length = 0;
+    this.canvas.clearContext(this.canvas.contextTop);
+    this._setShadow();
+    this.drawDot(pointer);
+  },
+
+  /**
+   * Invoked on mouse move
+   * @param {Object} pointer
+   */
+  onMouseMove: function(pointer) {
+    this.drawDot(pointer);
+  },
+
+  /**
+   * Invoked on mouse up
+   */
+  onMouseUp: function() {
+    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;
+    this.canvas.renderOnAddRemove = false;
+
+    var circles = [];
+
+    for (var i = 0, len = this.points.length; i < len; i++) {
+      var point = this.points[i],
+          circle = new fabric.Circle({
+            radius: point.radius,
+            left: point.x,
+            top: point.y,
+            originX: 'center',
+            originY: 'center',
+            fill: point.fill
+          });
+
+      this.shadow && circle.setShadow(this.shadow);
+
+      circles.push(circle);
+    }
+    var group = new fabric.Group(circles, { originX: 'center', originY: 'center' });
+    group.canvas = this.canvas;
+
+    this.canvas.add(group);
+    this.canvas.fire('path:created', { path: group });
+
+    this.canvas.clearContext(this.canvas.contextTop);
+    this._resetShadow();
+    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;
+    this.canvas.renderAll();
+  },
+
+  /**
+   * @param {Object} pointer
+   * @return {fabric.Point} Just added pointer point
+   */
+  addPoint: function(pointer) {
+    var pointerPoint = new fabric.Point(pointer.x, pointer.y),
+
+        circleRadius = fabric.util.getRandomInt(
+                        Math.max(0, this.width - 20), this.width + 20) / 2,
+
+        circleColor = new fabric.Color(this.color)
+                        .setAlpha(fabric.util.getRandomInt(0, 100) / 100)
+                        .toRgba();
+
+    pointerPoint.radius = circleRadius;
+    pointerPoint.fill = circleColor;
+
+    this.points.push(pointerPoint);
+
+    return pointerPoint;
+  }
+});
+
+
+/**
+ * SprayBrush class
+ * @class fabric.SprayBrush
+ */
+fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {
+
+  /**
+   * Width of a spray
+   * @type Number
+   * @default
+   */
+  width:              10,
+
+  /**
+   * Density of a spray (number of dots per chunk)
+   * @type Number
+   * @default
+   */
+  density:            20,
+
+  /**
+   * Width of spray dots
+   * @type Number
+   * @default
+   */
+  dotWidth:           1,
+
+  /**
+   * Width variance of spray dots
+   * @type Number
+   * @default
+   */
+  dotWidthVariance:   1,
+
+  /**
+   * Whether opacity of a dot should be random
+   * @type Boolean
+   * @default
+   */
+  randomOpacity:        false,
+
+  /**
+   * Whether overlapping dots (rectangles) should be removed (for performance reasons)
+   * @type Boolean
+   * @default
+   */
+  optimizeOverlapping:  true,
+
+  /**
+   * Constructor
+   * @param {fabric.Canvas} canvas
+   * @return {fabric.SprayBrush} Instance of a spray brush
+   */
+  initialize: function(canvas) {
+    this.canvas = canvas;
+    this.sprayChunks = [];
+  },
+
+  /**
+   * Invoked on mouse down
+   * @param {Object} pointer
+   */
+  onMouseDown: function(pointer) {
+    this.sprayChunks.length = 0;
+    this.canvas.clearContext(this.canvas.contextTop);
+    this._setShadow();
+
+    this.addSprayChunk(pointer);
+    this.render();
+  },
+
+  /**
+   * Invoked on mouse move
+   * @param {Object} pointer
+   */
+  onMouseMove: function(pointer) {
+    this.addSprayChunk(pointer);
+    this.render();
+  },
+
+  /**
+   * Invoked on mouse up
+   */
+  onMouseUp: function() {
+    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;
+    this.canvas.renderOnAddRemove = false;
+
+    var rects = [];
+
+    for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {
+      var sprayChunk = this.sprayChunks[i];
+
+      for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {
+
+        var rect = new fabric.Rect({
+          width: sprayChunk[j].width,
+          height: sprayChunk[j].width,
+          left: sprayChunk[j].x + 1,
+          top: sprayChunk[j].y + 1,
+          originX: 'center',
+          originY: 'center',
+          fill: this.color
+        });
+
+        this.shadow && rect.setShadow(this.shadow);
+        rects.push(rect);
+      }
+    }
+
+    if (this.optimizeOverlapping) {
+      rects = this._getOptimizedRects(rects);
+    }
+
+    var group = new fabric.Group(rects, { originX: 'center', originY: 'center' });
+    group.canvas = this.canvas;
+
+    this.canvas.add(group);
+    this.canvas.fire('path:created', { path: group });
+
+    this.canvas.clearContext(this.canvas.contextTop);
+    this._resetShadow();
+    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;
+    this.canvas.renderAll();
+  },
+
+  /**
+   * @private
+   * @param {Array} rects
+   */
+  _getOptimizedRects: function(rects) {
+
+    // avoid creating duplicate rects at the same coordinates
+    var uniqueRects = { }, key;
+
+    for (var i = 0, len = rects.length; i < len; i++) {
+      key = rects[i].left + '' + rects[i].top;
+      if (!uniqueRects[key]) {
+        uniqueRects[key] = rects[i];
+      }
+    }
+    var uniqueRectsArray = [];
+    for (key in uniqueRects) {
+      uniqueRectsArray.push(uniqueRects[key]);
+    }
+
+    return uniqueRectsArray;
+  },
+
+  /**
+   * Renders brush
+   */
+  render: function() {
+    var ctx = this.canvas.contextTop;
+    ctx.fillStyle = this.color;
+
+    var v = this.canvas.viewportTransform;
+    ctx.save();
+    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
+
+    for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
+      var point = this.sprayChunkPoints[i];
+      if (typeof point.opacity !== 'undefined') {
+        ctx.globalAlpha = point.opacity;
+      }
+      ctx.fillRect(point.x, point.y, point.width, point.width);
+    }
+    ctx.restore();
+  },
+
+  /**
+   * @param {Object} pointer
+   */
+  addSprayChunk: function(pointer) {
+    this.sprayChunkPoints = [];
+
+    var x, y, width, radius = this.width / 2;
+
+    for (var i = 0; i < this.density; i++) {
+
+      x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);
+      y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);
+
+      if (this.dotWidthVariance) {
+        width = fabric.util.getRandomInt(
+          // bottom clamp width to 1
+          Math.max(1, this.dotWidth - this.dotWidthVariance),
+          this.dotWidth + this.dotWidthVariance);
+      }
+      else {
+        width = this.dotWidth;
+      }
+
+      var point = new fabric.Point(x, y);
+      point.width = width;
+
+      if (this.randomOpacity) {
+        point.opacity = fabric.util.getRandomInt(0, 100) / 100;
+      }
+
+      this.sprayChunkPoints.push(point);
+    }
+
+    this.sprayChunks.push(this.sprayChunkPoints);
+  }
+});
+
+
+/**
+ * PatternBrush class
+ * @class fabric.PatternBrush
+ * @extends fabric.BaseBrush
+ */
+fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ {
+
+  getPatternSrc: function() {
+
+    var dotWidth = 20,
+        dotDistance = 5,
+        patternCanvas = fabric.document.createElement('canvas'),
+        patternCtx = patternCanvas.getContext('2d');
+
+    patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;
+
+    patternCtx.fillStyle = this.color;
+    patternCtx.beginPath();
+    patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);
+    patternCtx.closePath();
+    patternCtx.fill();
+
+    return patternCanvas;
+  },
+
+  getPatternSrcFunction: function() {
+    return String(this.getPatternSrc).replace('this.color', '"' + this.color + '"');
+  },
+
+  /**
+   * Creates "pattern" instance property
+   */
+  getPattern: function() {
+    return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat');
+  },
+
+  /**
+   * Sets brush styles
+   */
+  _setBrushStyles: function() {
+    this.callSuper('_setBrushStyles');
+    this.canvas.contextTop.strokeStyle = this.getPattern();
+  },
+
+  /**
+   * Creates path
+   */
+  createPath: function(pathData) {
+    var path = this.callSuper('createPath', pathData),
+        topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2);
+
+    path.stroke = new fabric.Pattern({
+      source: this.source || this.getPatternSrcFunction(),
+      offsetX: -topLeft.x,
+      offsetY: -topLeft.y
+    });
+    return path;
+  }
+});
+
+
+(function() {
+
+  var getPointer = fabric.util.getPointer,
+      degreesToRadians = fabric.util.degreesToRadians,
+      radiansToDegrees = fabric.util.radiansToDegrees,
+      atan2 = Math.atan2,
+      abs = Math.abs,
+      supportLineDash = fabric.StaticCanvas.supports('setLineDash'),
+
+      STROKE_OFFSET = 0.5;
+
+  /**
+   * Canvas class
+   * @class fabric.Canvas
+   * @extends fabric.StaticCanvas
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas}
+   * @see {@link fabric.Canvas#initialize} for constructor definition
+   *
+   * @fires object:added
+   * @fires object:modified
+   * @fires object:rotating
+   * @fires object:scaling
+   * @fires object:moving
+   * @fires object:selected
+   *
+   * @fires before:selection:cleared
+   * @fires selection:cleared
+   * @fires selection:created
+   *
+   * @fires path:created
+   * @fires mouse:down
+   * @fires mouse:move
+   * @fires mouse:up
+   * @fires mouse:over
+   * @fires mouse:out
+   *
+   */
+  fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {
+
+    /**
+     * Constructor
+     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on
+     * @param {Object} [options] Options object
+     * @return {Object} thisArg
+     */
+    initialize: function(el, options) {
+      options || (options = { });
+
+      this._initStatic(el, options);
+      this._initInteractive();
+      this._createCacheCanvas();
+    },
+
+    /**
+     * When true, objects can be transformed by one side (unproportionally)
+     * @type Boolean
+     * @default
+     */
+    uniScaleTransform:      false,
+
+    /**
+     * Indicates which key enable unproportional scaling
+     * values: 'altKey', 'shiftKey', 'ctrlKey'.
+     * If `null` or 'none' or any other string that is not a modifier key
+     * feature is disabled feature disabled.
+     * @since 1.6.2
+     * @type String
+     * @default
+     */
+    uniScaleKey:           'shiftKey',
+
+    /**
+     * When true, objects use center point as the origin of scale transformation.
+     * <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
+     * @since 1.3.4
+     * @type Boolean
+     * @default
+     */
+    centeredScaling:        false,
+
+    /**
+     * When true, objects use center point as the origin of rotate transformation.
+     * <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
+     * @since 1.3.4
+     * @type Boolean
+     * @default
+     */
+    centeredRotation:       false,
+
+    /**
+     * Indicates which key enable centered Transfrom
+     * values: 'altKey', 'shiftKey', 'ctrlKey'.
+     * If `null` or 'none' or any other string that is not a modifier key
+     * feature is disabled feature disabled.
+     * @since 1.6.2
+     * @type String
+     * @default
+     */
+    centeredKey:           'altKey',
+
+    /**
+     * Indicates which key enable alternate action on corner
+     * values: 'altKey', 'shiftKey', 'ctrlKey'.
+     * If `null` or 'none' or any other string that is not a modifier key
+     * feature is disabled feature disabled.
+     * @since 1.6.2
+     * @type String
+     * @default
+     */
+    altActionKey:           'shiftKey',
+
+    /**
+     * Indicates that canvas is interactive. This property should not be changed.
+     * @type Boolean
+     * @default
+     */
+    interactive:            true,
+
+    /**
+     * Indicates whether group selection should be enabled
+     * @type Boolean
+     * @default
+     */
+    selection:              true,
+
+    /**
+     * Indicates which key enable multiple click selection
+     * values: 'altKey', 'shiftKey', 'ctrlKey'.
+     * If `null` or 'none' or any other string that is not a modifier key
+     * feature is disabled feature disabled.
+     * @since 1.6.2
+     * @type String
+     * @default
+     */
+    selectionKey:           'shiftKey',
+
+    /**
+     * Indicates which key enable alternative selection
+     * in case of target overlapping with active object
+     * values: 'altKey', 'shiftKey', 'ctrlKey'.
+     * If `null` or 'none' or any other string that is not a modifier key
+     * feature is disabled feature disabled.
+     * @since 1.6.5
+     * @type null|String
+     * @default
+     */
+    altSelectionKey:           null,
+
+    /**
+     * Color of selection
+     * @type String
+     * @default
+     */
+    selectionColor:         'rgba(100, 100, 255, 0.3)', // blue
+
+    /**
+     * Default dash array pattern
+     * If not empty the selection border is dashed
+     * @type Array
+     */
+    selectionDashArray:     [],
+
+    /**
+     * Color of the border of selection (usually slightly darker than color of selection itself)
+     * @type String
+     * @default
+     */
+    selectionBorderColor:   'rgba(255, 255, 255, 0.3)',
+
+    /**
+     * Width of a line used in object/group selection
+     * @type Number
+     * @default
+     */
+    selectionLineWidth:     1,
+
+    /**
+     * Default cursor value used when hovering over an object on canvas
+     * @type String
+     * @default
+     */
+    hoverCursor:            'move',
+
+    /**
+     * Default cursor value used when moving an object on canvas
+     * @type String
+     * @default
+     */
+    moveCursor:             'move',
+
+    /**
+     * Default cursor value used for the entire canvas
+     * @type String
+     * @default
+     */
+    defaultCursor:          'default',
+
+    /**
+     * Cursor value used during free drawing
+     * @type String
+     * @default
+     */
+    freeDrawingCursor:      'crosshair',
+
+    /**
+     * Cursor value used for rotation point
+     * @type String
+     * @default
+     */
+    rotationCursor:         'crosshair',
+
+    /**
+     * Default element class that's given to wrapper (div) element of canvas
+     * @type String
+     * @default
+     */
+    containerClass:         'canvas-container',
+
+    /**
+     * When true, object detection happens on per-pixel basis rather than on per-bounding-box
+     * @type Boolean
+     * @default
+     */
+    perPixelTargetFind:     false,
+
+    /**
+     * Number of pixels around target pixel to tolerate (consider active) during object detection
+     * @type Number
+     * @default
+     */
+    targetFindTolerance:    0,
+
+    /**
+     * When true, target detection is skipped when hovering over canvas. This can be used to improve performance.
+     * @type Boolean
+     * @default
+     */
+    skipTargetFind:         false,
+
+    /**
+     * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.
+     * After mousedown, mousemove creates a shape,
+     * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.
+     * @tutorial {@link http://fabricjs.com/fabric-intro-part-4#free_drawing}
+     * @type Boolean
+     * @default
+     */
+    isDrawingMode:          false,
+
+    /**
+     * Indicates whether objects should remain in current stack position when selected.
+     * When false objects are brought to top and rendered as part of the selection group
+     * @type Boolean
+     * @default
+     */
+    preserveObjectStacking: false,
+
+    /**
+     * Indicates the angle that an object will lock to while rotating.
+     * @type Number
+     * @since 1.6.7
+     * @default
+     */
+    snapAngle: 0,
+
+    /**
+     * Indicates the distance from the snapAngle the rotation will lock to the snapAngle.
+     * When `null`, the snapThreshold will default to the snapAngle.
+     * @type null|Number
+     * @since 1.6.7
+     * @default
+     */
+    snapThreshold: null,
+
+    /**
+     * Indicates if the right click on canvas can output the context menu or not
+     * @type Boolean
+     * @since 1.6.5
+     * @default
+     */
+    stopContextMenu: false,
+
+    /**
+     * Indicates if the canvas can fire right click events
+     * @type Boolean
+     * @since 1.6.5
+     * @default
+     */
+    fireRightClick: false,
+
+    /**
+     * @private
+     */
+    _initInteractive: function() {
+      this._currentTransform = null;
+      this._groupSelector = null;
+      this._initWrapperElement();
+      this._createUpperCanvas();
+      this._initEventListeners();
+
+      this._initRetinaScaling();
+
+      this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);
+
+      this.calcOffset();
+    },
+
+    /**
+     * Divides objects in two groups, one to render immediately
+     * and one to render as activeGroup.
+     * @return {Array} objects to render immediately and pushes the other in the activeGroup.
+     */
+    _chooseObjectsToRender: function() {
+      var activeGroup = this.getActiveGroup(),
+          activeObject = this.getActiveObject(),
+          object, objsToRender = [], activeGroupObjects = [];
+
+      if ((activeGroup || activeObject) && !this.preserveObjectStacking) {
+        for (var i = 0, length = this._objects.length; i < length; i++) {
+          object = this._objects[i];
+          if ((!activeGroup || !activeGroup.contains(object)) && object !== activeObject) {
+            objsToRender.push(object);
+          }
+          else {
+            activeGroupObjects.push(object);
+          }
+        }
+        if (activeGroup) {
+          activeGroup._set('_objects', activeGroupObjects);
+          objsToRender.push(activeGroup);
+        }
+        activeObject && objsToRender.push(activeObject);
+      }
+      else {
+        objsToRender = this._objects;
+      }
+      return objsToRender;
+    },
+
+    /**
+     * Renders both the top canvas and the secondary container canvas.
+     * @return {fabric.Canvas} instance
+     * @chainable
+     */
+    renderAll: function () {
+      if (this.contextTopDirty && !this._groupSelector && !this.isDrawingMode) {
+        this.clearContext(this.contextTop);
+        this.contextTopDirty = false;
+      }
+      var canvasToDrawOn = this.contextContainer;
+      this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());
+      return this;
+    },
+
+    /**
+     * Method to render only the top canvas.
+     * Also used to render the group selection box.
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    renderTop: function () {
+      var ctx = this.contextTop;
+      this.clearContext(ctx);
+
+      // we render the top context - last object
+      if (this.selection && this._groupSelector) {
+        this._drawSelection(ctx);
+      }
+
+      this.fire('after:render');
+      this.contextTopDirty = true;
+      return this;
+    },
+
+    /**
+     * Resets the current transform to its original values and chooses the type of resizing based on the event
+     * @private
+     */
+    _resetCurrentTransform: function() {
+      var t = this._currentTransform;
+
+      t.target.set({
+        scaleX: t.original.scaleX,
+        scaleY: t.original.scaleY,
+        skewX: t.original.skewX,
+        skewY: t.original.skewY,
+        left: t.original.left,
+        top: t.original.top
+      });
+
+      if (this._shouldCenterTransform(t.target)) {
+        if (t.action === 'rotate') {
+          this._setOriginToCenter(t.target);
+        }
+        else {
+          if (t.originX !== 'center') {
+            if (t.originX === 'right') {
+              t.mouseXSign = -1;
+            }
+            else {
+              t.mouseXSign = 1;
+            }
+          }
+          if (t.originY !== 'center') {
+            if (t.originY === 'bottom') {
+              t.mouseYSign = -1;
+            }
+            else {
+              t.mouseYSign = 1;
+            }
+          }
+
+          t.originX = 'center';
+          t.originY = 'center';
+        }
+      }
+      else {
+        t.originX = t.original.originX;
+        t.originY = t.original.originY;
+      }
+    },
+
+    /**
+     * Checks if point is contained within an area of given object
+     * @param {Event} e Event object
+     * @param {fabric.Object} target Object to test against
+     * @param {Object} [point] x,y object of point coordinates we want to check.
+     * @return {Boolean} true if point is contained within an area of given object
+     */
+    containsPoint: function (e, target, point) {
+      var ignoreZoom = true,
+          pointer = point || this.getPointer(e, ignoreZoom),
+          xy;
+
+      if (target.group && target.group === this.getActiveGroup()) {
+        xy = this._normalizePointer(target.group, pointer);
+      }
+      else {
+        xy = { x: pointer.x, y: pointer.y };
+      }
+      // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html
+      // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
+      return (target.containsPoint(xy) || target._findTargetCorner(pointer));
+    },
+
+    /**
+     * @private
+     */
+    _normalizePointer: function (object, pointer) {
+      var m = object.calcTransformMatrix(),
+          invertedM = fabric.util.invertTransform(m),
+          vpt = this.viewportTransform,
+          vptPointer = this.restorePointerVpt(pointer),
+          p = fabric.util.transformPoint(vptPointer, invertedM);
+      return fabric.util.transformPoint(p, vpt);
+    },
+
+    /**
+     * Returns true if object is transparent at a certain location
+     * @param {fabric.Object} target Object to check
+     * @param {Number} x Left coordinate
+     * @param {Number} y Top coordinate
+     * @return {Boolean}
+     */
+    isTargetTransparent: function (target, x, y) {
+      var hasBorders = target.hasBorders,
+          transparentCorners = target.transparentCorners,
+          ctx = this.contextCache,
+          originalColor = target.selectionBackgroundColor;
+
+      target.hasBorders = target.transparentCorners = false;
+      target.selectionBackgroundColor = '';
+
+      ctx.save();
+      ctx.transform.apply(ctx, this.viewportTransform);
+      target.render(ctx);
+      ctx.restore();
+
+      target.active && target._renderControls(ctx);
+
+      target.hasBorders = hasBorders;
+      target.transparentCorners = transparentCorners;
+      target.selectionBackgroundColor = originalColor;
+
+      var isTransparent = fabric.util.isTransparent(
+        ctx, x, y, this.targetFindTolerance);
+
+      this.clearContext(ctx);
+
+      return isTransparent;
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object
+     * @param {fabric.Object} target
+     */
+    _shouldClearSelection: function (e, target) {
+      var activeGroup = this.getActiveGroup(),
+          activeObject = this.getActiveObject();
+
+      return (
+        !target
+        ||
+        (target &&
+          activeGroup &&
+          !activeGroup.contains(target) &&
+          activeGroup !== target &&
+          !e[this.selectionKey])
+        ||
+        (target && !target.evented)
+        ||
+        (target &&
+          !target.selectable &&
+          activeObject &&
+          activeObject !== target)
+      );
+    },
+
+    /**
+     * @private
+     * @param {fabric.Object} target
+     */
+    _shouldCenterTransform: function (target) {
+      if (!target) {
+        return;
+      }
+
+      var t = this._currentTransform,
+          centerTransform;
+
+      if (t.action === 'scale' || t.action === 'scaleX' || t.action === 'scaleY') {
+        centerTransform = this.centeredScaling || target.centeredScaling;
+      }
+      else if (t.action === 'rotate') {
+        centerTransform = this.centeredRotation || target.centeredRotation;
+      }
+
+      return centerTransform ? !t.altKey : t.altKey;
+    },
+
+    /**
+     * @private
+     */
+    _getOriginFromCorner: function(target, corner) {
+      var origin = {
+        x: target.originX,
+        y: target.originY
+      };
+
+      if (corner === 'ml' || corner === 'tl' || corner === 'bl') {
+        origin.x = 'right';
+      }
+      else if (corner === 'mr' || corner === 'tr' || corner === 'br') {
+        origin.x = 'left';
+      }
+
+      if (corner === 'tl' || corner === 'mt' || corner === 'tr') {
+        origin.y = 'bottom';
+      }
+      else if (corner === 'bl' || corner === 'mb' || corner === 'br') {
+        origin.y = 'top';
+      }
+
+      return origin;
+    },
+
+    /**
+     * @private
+     */
+    _getActionFromCorner: function(target, corner, e) {
+      if (!corner) {
+        return 'drag';
+      }
+
+      switch (corner) {
+        case 'mtr':
+          return 'rotate';
+        case 'ml':
+        case 'mr':
+          return e[this.altActionKey] ? 'skewY' : 'scaleX';
+        case 'mt':
+        case 'mb':
+          return e[this.altActionKey] ? 'skewX' : 'scaleY';
+        default:
+          return 'scale';
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object
+     * @param {fabric.Object} target
+     */
+    _setupCurrentTransform: function (e, target) {
+      if (!target) {
+        return;
+      }
+
+      var pointer = this.getPointer(e),
+          corner = target._findTargetCorner(this.getPointer(e, true)),
+          action = this._getActionFromCorner(target, corner, e),
+          origin = this._getOriginFromCorner(target, corner);
+
+      this._currentTransform = {
+        target: target,
+        action: action,
+        corner: corner,
+        scaleX: target.scaleX,
+        scaleY: target.scaleY,
+        skewX: target.skewX,
+        skewY: target.skewY,
+        offsetX: pointer.x - target.left,
+        offsetY: pointer.y - target.top,
+        originX: origin.x,
+        originY: origin.y,
+        ex: pointer.x,
+        ey: pointer.y,
+        lastX: pointer.x,
+        lastY: pointer.y,
+        left: target.left,
+        top: target.top,
+        theta: degreesToRadians(target.angle),
+        width: target.width * target.scaleX,
+        mouseXSign: 1,
+        mouseYSign: 1,
+        shiftKey: e.shiftKey,
+        altKey: e[this.centeredKey]
+      };
+
+      this._currentTransform.original = {
+        left: target.left,
+        top: target.top,
+        scaleX: target.scaleX,
+        scaleY: target.scaleY,
+        skewX: target.skewX,
+        skewY: target.skewY,
+        originX: origin.x,
+        originY: origin.y
+      };
+
+      this._resetCurrentTransform();
+    },
+
+    /**
+     * Translates object by "setting" its left/top
+     * @private
+     * @param {Number} x pointer's x coordinate
+     * @param {Number} y pointer's y coordinate
+     * @return {Boolean} true if the translation occurred
+     */
+    _translateObject: function (x, y) {
+      var transform = this._currentTransform,
+          target = transform.target,
+          newLeft = x - transform.offsetX,
+          newTop = y - transform.offsetY,
+          moveX = !target.get('lockMovementX') && target.left !== newLeft,
+          moveY = !target.get('lockMovementY') && target.top !== newTop;
+
+      moveX && target.set('left', newLeft);
+      moveY && target.set('top', newTop);
+      return moveX || moveY;
+    },
+
+    /**
+     * Check if we are increasing a positive skew or lower it,
+     * checking mouse direction and pressed corner.
+     * @private
+     */
+    _changeSkewTransformOrigin: function(mouseMove, t, by) {
+      var property = 'originX', origins = { 0: 'center' },
+          skew = t.target.skewX, originA = 'left', originB = 'right',
+          corner = t.corner === 'mt' || t.corner === 'ml' ? 1 : -1,
+          flipSign = 1;
+
+      mouseMove = mouseMove > 0 ? 1 : -1;
+      if (by === 'y') {
+        skew = t.target.skewY;
+        originA = 'top';
+        originB = 'bottom';
+        property = 'originY';
+      }
+      origins[-1] = originA;
+      origins[1] = originB;
+
+      t.target.flipX && (flipSign *= -1);
+      t.target.flipY && (flipSign *= -1);
+
+      if (skew === 0) {
+        t.skewSign = -corner * mouseMove * flipSign;
+        t[property] = origins[-mouseMove];
+      }
+      else {
+        skew = skew > 0 ? 1 : -1;
+        t.skewSign = skew;
+        t[property] = origins[skew * corner * flipSign];
+      }
+    },
+
+    /**
+     * Skew object by mouse events
+     * @private
+     * @param {Number} x pointer's x coordinate
+     * @param {Number} y pointer's y coordinate
+     * @param {String} by Either 'x' or 'y'
+     * @return {Boolean} true if the skewing occurred
+     */
+    _skewObject: function (x, y, by) {
+      var t = this._currentTransform,
+          target = t.target, skewed = false,
+          lockSkewingX = target.get('lockSkewingX'),
+          lockSkewingY = target.get('lockSkewingY');
+
+      if ((lockSkewingX && by === 'x') || (lockSkewingY && by === 'y')) {
+        return false;
+      }
+
+      // Get the constraint point
+      var center = target.getCenterPoint(),
+          actualMouseByCenter = target.toLocalPoint(new fabric.Point(x, y), 'center', 'center')[by],
+          lastMouseByCenter = target.toLocalPoint(new fabric.Point(t.lastX, t.lastY), 'center', 'center')[by],
+          actualMouseByOrigin, constraintPosition, dim = target._getTransformedDimensions();
+
+      this._changeSkewTransformOrigin(actualMouseByCenter - lastMouseByCenter, t, by);
+      actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by];
+      constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY);
+      // Actually skew the object
+      skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim);
+      t.lastX = x;
+      t.lastY = y;
+      // Make sure the constraints apply
+      target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
+      return skewed;
+    },
+
+    /**
+     * Set object skew
+     * @private
+     * @return {Boolean} true if the skewing occurred
+     */
+    _setObjectSkew: function(localMouse, transform, by, _dim) {
+      var target = transform.target, newValue, skewed = false,
+          skewSign = transform.skewSign, newDim, dimNoSkew,
+          otherBy, _otherBy, _by, newDimMouse, skewX, skewY;
+
+      if (by === 'x') {
+        otherBy = 'y';
+        _otherBy = 'Y';
+        _by = 'X';
+        skewX = 0;
+        skewY = target.skewY;
+      }
+      else {
+        otherBy = 'x';
+        _otherBy = 'X';
+        _by = 'Y';
+        skewX = target.skewX;
+        skewY = 0;
+      }
+
+      dimNoSkew = target._getTransformedDimensions(skewX, skewY);
+      newDimMouse = 2 * Math.abs(localMouse) - dimNoSkew[by];
+      if (newDimMouse <= 2) {
+        newValue = 0;
+      }
+      else {
+        newValue = skewSign * Math.atan((newDimMouse / target['scale' + _by]) /
+                                        (dimNoSkew[otherBy] / target['scale' + _otherBy]));
+        newValue = fabric.util.radiansToDegrees(newValue);
+      }
+      skewed = target['skew' + _by] !== newValue;
+      target.set('skew' + _by, newValue);
+      if (target['skew' + _otherBy] !== 0) {
+        newDim = target._getTransformedDimensions();
+        newValue = (_dim[otherBy] / newDim[otherBy]) * target['scale' + _otherBy];
+        target.set('scale' + _otherBy, newValue);
+      }
+      return skewed;
+    },
+
+    /**
+     * Scales object by invoking its scaleX/scaleY methods
+     * @private
+     * @param {Number} x pointer's x coordinate
+     * @param {Number} y pointer's y coordinate
+     * @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object.
+     *                    When not provided, an object is scaled by both dimensions equally
+     * @return {Boolean} true if the scaling occurred
+     */
+    _scaleObject: function (x, y, by) {
+      var t = this._currentTransform,
+          target = t.target,
+          lockScalingX = target.get('lockScalingX'),
+          lockScalingY = target.get('lockScalingY'),
+          lockScalingFlip = target.get('lockScalingFlip');
+
+      if (lockScalingX && lockScalingY) {
+        return false;
+      }
+
+      // Get the constraint point
+      var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),
+          localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY),
+          dim = target._getTransformedDimensions(), scaled = false;
+
+      this._setLocalMouse(localMouse, t);
+
+      // Actually scale the object
+      scaled = this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim);
+
+      // Make sure the constraints apply
+      target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
+      return scaled;
+    },
+
+    /**
+     * @private
+     * @return {Boolean} true if the scaling occurred
+     */
+    _setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
+      var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false,
+          changeX, changeY, scaleX, scaleY;
+
+      scaleX = localMouse.x * target.scaleX / _dim.x;
+      scaleY = localMouse.y * target.scaleY / _dim.y;
+      changeX = target.scaleX !== scaleX;
+      changeY = target.scaleY !== scaleY;
+
+      if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) {
+        forbidScalingX = true;
+      }
+
+      if (lockScalingFlip && scaleY <= 0 && scaleY < target.scaleY) {
+        forbidScalingY = true;
+      }
+
+      if (by === 'equally' && !lockScalingX && !lockScalingY) {
+        forbidScalingX || forbidScalingY || (scaled = this._scaleObjectEqually(localMouse, target, transform, _dim));
+      }
+      else if (!by) {
+        forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));
+        forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
+      }
+      else if (by === 'x' && !target.get('lockUniScaling')) {
+        forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));
+      }
+      else if (by === 'y' && !target.get('lockUniScaling')) {
+        forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
+      }
+      transform.newScaleX = scaleX;
+      transform.newScaleY = scaleY;
+      forbidScalingX || forbidScalingY || this._flipObject(transform, by);
+      return scaled;
+    },
+
+    /**
+     * @private
+     * @return {Boolean} true if the scaling occurred
+     */
+    _scaleObjectEqually: function(localMouse, target, transform, _dim) {
+
+      var dist = localMouse.y + localMouse.x,
+          lastDist = _dim.y * transform.original.scaleY / target.scaleY +
+                     _dim.x * transform.original.scaleX / target.scaleX,
+          scaled;
+
+      // We use transform.scaleX/Y instead of target.scaleX/Y
+      // because the object may have a min scale and we'll loose the proportions
+      transform.newScaleX = transform.original.scaleX * dist / lastDist;
+      transform.newScaleY = transform.original.scaleY * dist / lastDist;
+      scaled = transform.newScaleX !== target.scaleX || transform.newScaleY !== target.scaleY;
+      target.set('scaleX', transform.newScaleX);
+      target.set('scaleY', transform.newScaleY);
+      return scaled;
+    },
+
+    /**
+     * @private
+     */
+    _flipObject: function(transform, by) {
+      if (transform.newScaleX < 0 && by !== 'y') {
+        if (transform.originX === 'left') {
+          transform.originX = 'right';
+        }
+        else if (transform.originX === 'right') {
+          transform.originX = 'left';
+        }
+      }
+
+      if (transform.newScaleY < 0 && by !== 'x') {
+        if (transform.originY === 'top') {
+          transform.originY = 'bottom';
+        }
+        else if (transform.originY === 'bottom') {
+          transform.originY = 'top';
+        }
+      }
+    },
+
+    /**
+     * @private
+     */
+    _setLocalMouse: function(localMouse, t) {
+      var target = t.target;
+
+      if (t.originX === 'right') {
+        localMouse.x *= -1;
+      }
+      else if (t.originX === 'center') {
+        localMouse.x *= t.mouseXSign * 2;
+        if (localMouse.x < 0) {
+          t.mouseXSign = -t.mouseXSign;
+        }
+      }
+
+      if (t.originY === 'bottom') {
+        localMouse.y *= -1;
+      }
+      else if (t.originY === 'center') {
+        localMouse.y *= t.mouseYSign * 2;
+        if (localMouse.y < 0) {
+          t.mouseYSign = -t.mouseYSign;
+        }
+      }
+
+      // adjust the mouse coordinates when dealing with padding
+      if (abs(localMouse.x) > target.padding) {
+        if (localMouse.x < 0) {
+          localMouse.x += target.padding;
+        }
+        else {
+          localMouse.x -= target.padding;
+        }
+      }
+      else { // mouse is within the padding, set to 0
+        localMouse.x = 0;
+      }
+
+      if (abs(localMouse.y) > target.padding) {
+        if (localMouse.y < 0) {
+          localMouse.y += target.padding;
+        }
+        else {
+          localMouse.y -= target.padding;
+        }
+      }
+      else {
+        localMouse.y = 0;
+      }
+    },
+
+    /**
+     * Rotates object by invoking its rotate method
+     * @private
+     * @param {Number} x pointer's x coordinate
+     * @param {Number} y pointer's y coordinate
+     * @return {Boolean} true if the rotation occurred
+     */
+    _rotateObject: function (x, y) {
+
+      var t = this._currentTransform;
+
+      if (t.target.get('lockRotation')) {
+        return false;
+      }
+
+      var lastAngle = atan2(t.ey - t.top, t.ex - t.left),
+          curAngle = atan2(y - t.top, x - t.left),
+          angle = radiansToDegrees(curAngle - lastAngle + t.theta),
+          hasRoated = true;
+
+      // normalize angle to positive value
+      if (angle < 0) {
+        angle = 360 + angle;
+      }
+
+      angle %= 360
+
+      if (t.target.snapAngle > 0) {
+        var snapAngle  = t.target.snapAngle,
+            snapThreshold  = t.target.snapThreshold || snapAngle,
+            rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle,
+            leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;
+
+        if (Math.abs(angle - leftAngleLocked) < snapThreshold) {
+          angle = leftAngleLocked;
+        }
+        else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {
+          angle = rightAngleLocked;
+        }
+
+        if (t.target.angle === angle) {
+          hasRoated = false
+        }
+      }
+
+      t.target.angle = angle;
+      return hasRoated;
+    },
+
+    /**
+     * Set the cursor type of the canvas element
+     * @param {String} value Cursor type of the canvas element.
+     * @see http://www.w3.org/TR/css3-ui/#cursor
+     */
+    setCursor: function (value) {
+      this.upperCanvasEl.style.cursor = value;
+    },
+
+    /**
+     * @param {fabric.Object} target to reset transform
+     * @private
+     */
+    _resetObjectTransform: function (target) {
+      target.scaleX = 1;
+      target.scaleY = 1;
+      target.skewX = 0;
+      target.skewY = 0;
+      target.setAngle(0);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx to draw the selection on
+     */
+    _drawSelection: function (ctx) {
+      var groupSelector = this._groupSelector,
+          left = groupSelector.left,
+          top = groupSelector.top,
+          aleft = abs(left),
+          atop = abs(top);
+
+      if (this.selectionColor) {
+        ctx.fillStyle = this.selectionColor;
+
+        ctx.fillRect(
+          groupSelector.ex - ((left > 0) ? 0 : -left),
+          groupSelector.ey - ((top > 0) ? 0 : -top),
+          aleft,
+          atop
+        );
+      }
+
+      if (!this.selectionLineWidth || !this.selectionBorderColor) {
+        return;
+      }
+      ctx.lineWidth = this.selectionLineWidth;
+      ctx.strokeStyle = this.selectionBorderColor;
+
+      // selection border
+      if (this.selectionDashArray.length > 1 && !supportLineDash) {
+
+        var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
+            py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop);
+
+        ctx.beginPath();
+
+        fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray);
+        fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray);
+        fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray);
+        fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray);
+
+        ctx.closePath();
+        ctx.stroke();
+      }
+      else {
+        fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);
+        ctx.strokeRect(
+          groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
+          groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),
+          aleft,
+          atop
+        );
+      }
+    },
+
+    /**
+     * Method that determines what object we are clicking on
+     * @param {Event} e mouse event
+     * @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through
+     */
+    findTarget: function (e, skipGroup) {
+      if (this.skipTargetFind) {
+        return;
+      }
+
+      var ignoreZoom = true,
+          pointer = this.getPointer(e, ignoreZoom),
+          activeGroup = this.getActiveGroup(),
+          activeObject = this.getActiveObject(),
+          activeTarget;
+
+      // first check current group (if one exists)
+      // active group does not check sub targets like normal groups.
+      // if active group just exits.
+      if (activeGroup && !skipGroup && this._checkTarget(pointer, activeGroup)) {
+        this._fireOverOutEvents(activeGroup, e);
+        return activeGroup;
+      }
+      // if we hit the corner of an activeObject, let's return that.
+      if (activeObject && activeObject._findTargetCorner(pointer)) {
+        this._fireOverOutEvents(activeObject, e);
+        return activeObject;
+      }
+      if (activeObject && this._checkTarget(pointer, activeObject)) {
+        if (!this.preserveObjectStacking) {
+          this._fireOverOutEvents(activeObject, e);
+          return activeObject;
+        }
+        else {
+          activeTarget = activeObject;
+        }
+      }
+
+      this.targets = [];
+
+      var target = this._searchPossibleTargets(this._objects, pointer);
+      if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) {
+        target = activeTarget;
+      }
+      this._fireOverOutEvents(target, e);
+      return target;
+    },
+
+    /**
+     * @private
+     */
+    _fireOverOutEvents: function(target, e) {
+      if (target) {
+        if (this._hoveredTarget !== target) {
+          if (this._hoveredTarget) {
+            this.fire('mouse:out', { target: this._hoveredTarget, e: e });
+            this._hoveredTarget.fire('mouseout');
+          }
+          this.fire('mouse:over', { target: target, e: e });
+          target.fire('mouseover');
+          this._hoveredTarget = target;
+        }
+      }
+      else if (this._hoveredTarget) {
+        this.fire('mouse:out', { target: this._hoveredTarget, e: e });
+        this._hoveredTarget.fire('mouseout');
+        this._hoveredTarget = null;
+      }
+    },
+
+    /**
+     * @private
+     */
+    _checkTarget: function(pointer, obj) {
+      if (obj &&
+          obj.visible &&
+          obj.evented &&
+          this.containsPoint(null, obj, pointer)){
+        if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {
+          var isTransparent = this.isTargetTransparent(obj, pointer.x, pointer.y);
+          if (!isTransparent) {
+            return true;
+          }
+        }
+        else {
+          return true;
+        }
+      }
+    },
+
+    /**
+     * @private
+     */
+    _searchPossibleTargets: function(objects, pointer) {
+
+      // Cache all targets where their bounding box contains point.
+      var target, i = objects.length, normalizedPointer, subTarget;
+      // Do not check for currently grouped objects, since we check the parent group itself.
+      // untill we call this function specifically to search inside the activeGroup
+      while (i--) {
+        if (this._checkTarget(pointer, objects[i])) {
+          target = objects[i];
+          if (target.type === 'group' && target.subTargetCheck) {
+            normalizedPointer = this._normalizePointer(target, pointer);
+            subTarget = this._searchPossibleTargets(target._objects, normalizedPointer);
+            subTarget && this.targets.push(subTarget);
+          }
+          break;
+        }
+      }
+      return target;
+    },
+
+    /**
+     * Returns pointer coordinates without the effect of the viewport
+     * @param {Object} pointer with "x" and "y" number values
+     * @return {Object} object with "x" and "y" number values
+     */
+    restorePointerVpt: function(pointer) {
+      return fabric.util.transformPoint(
+        pointer,
+        fabric.util.invertTransform(this.viewportTransform)
+      );
+    },
+
+    /**
+     * Returns pointer coordinates relative to canvas.
+     * @param {Event} e
+     * @param {Boolean} ignoreZoom
+     * @return {Object} object with "x" and "y" number values
+     */
+    getPointer: function (e, ignoreZoom, upperCanvasEl) {
+      if (!upperCanvasEl) {
+        upperCanvasEl = this.upperCanvasEl;
+      }
+      var pointer = getPointer(e),
+          bounds = upperCanvasEl.getBoundingClientRect(),
+          boundsWidth = bounds.width || 0,
+          boundsHeight = bounds.height || 0,
+          cssScale;
+
+      if (!boundsWidth || !boundsHeight ) {
+        if ('top' in bounds && 'bottom' in bounds) {
+          boundsHeight = Math.abs( bounds.top - bounds.bottom );
+        }
+        if ('right' in bounds && 'left' in bounds) {
+          boundsWidth = Math.abs( bounds.right - bounds.left );
+        }
+      }
+
+      this.calcOffset();
+
+      pointer.x = pointer.x - this._offset.left;
+      pointer.y = pointer.y - this._offset.top;
+      if (!ignoreZoom) {
+        pointer = this.restorePointerVpt(pointer);
+      }
+
+      if (boundsWidth === 0 || boundsHeight === 0) {
+        // If bounds are not available (i.e. not visible), do not apply scale.
+        cssScale = { width: 1, height: 1 };
+      }
+      else {
+        cssScale = {
+          width: upperCanvasEl.width / boundsWidth,
+          height: upperCanvasEl.height / boundsHeight
+        };
+      }
+
+      return {
+        x: pointer.x * cssScale.width,
+        y: pointer.y * cssScale.height
+      };
+    },
+
+    /**
+     * @private
+     * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized
+     */
+    _createUpperCanvas: function () {
+      var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/, '');
+
+      this.upperCanvasEl = this._createCanvasElement();
+      fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);
+
+      this.wrapperEl.appendChild(this.upperCanvasEl);
+
+      this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl);
+      this._applyCanvasStyle(this.upperCanvasEl);
+      this.contextTop = this.upperCanvasEl.getContext('2d');
+    },
+
+    /**
+     * @private
+     */
+    _createCacheCanvas: function () {
+      this.cacheCanvasEl = this._createCanvasElement();
+      this.cacheCanvasEl.setAttribute('width', this.width);
+      this.cacheCanvasEl.setAttribute('height', this.height);
+      this.contextCache = this.cacheCanvasEl.getContext('2d');
+    },
+
+    /**
+     * @private
+     */
+    _initWrapperElement: function () {
+      this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {
+        'class': this.containerClass
+      });
+      fabric.util.setStyle(this.wrapperEl, {
+        width: this.getWidth() + 'px',
+        height: this.getHeight() + 'px',
+        position: 'relative'
+      });
+      fabric.util.makeElementUnselectable(this.wrapperEl);
+    },
+
+    /**
+     * @private
+     * @param {HTMLElement} element canvas element to apply styles on
+     */
+    _applyCanvasStyle: function (element) {
+      var width = this.getWidth() || element.width,
+          height = this.getHeight() || element.height;
+
+      fabric.util.setStyle(element, {
+        position: 'absolute',
+        width: width + 'px',
+        height: height + 'px',
+        left: 0,
+        top: 0
+      });
+      element.width = width;
+      element.height = height;
+      fabric.util.makeElementUnselectable(element);
+    },
+
+    /**
+     * Copys the the entire inline style from one element (fromEl) to another (toEl)
+     * @private
+     * @param {Element} fromEl Element style is copied from
+     * @param {Element} toEl Element copied style is applied to
+     */
+    _copyCanvasStyle: function (fromEl, toEl) {
+      toEl.style.cssText = fromEl.style.cssText;
+    },
+
+    /**
+     * Returns context of canvas where object selection is drawn
+     * @return {CanvasRenderingContext2D}
+     */
+    getSelectionContext: function() {
+      return this.contextTop;
+    },
+
+    /**
+     * Returns &lt;canvas> element on which object selection is drawn
+     * @return {HTMLCanvasElement}
+     */
+    getSelectionElement: function () {
+      return this.upperCanvasEl;
+    },
+
+    /**
+     * @private
+     * @param {Object} object
+     */
+    _setActiveObject: function(object) {
+      if (this._activeObject) {
+        this._activeObject.set('active', false);
+      }
+      this._activeObject = object;
+      object.set('active', true);
+    },
+
+    /**
+     * Sets given object as the only active object on canvas
+     * @param {fabric.Object} object Object to set as an active one
+     * @param {Event} [e] Event (passed along when firing "object:selected")
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    setActiveObject: function (object, e) {
+      this._setActiveObject(object);
+      this.renderAll();
+      this.fire('object:selected', { target: object, e: e });
+      object.fire('selected', { e: e });
+      return this;
+    },
+
+    /**
+     * Returns currently active object
+     * @return {fabric.Object} active object
+     */
+    getActiveObject: function () {
+      return this._activeObject;
+    },
+
+    /**
+     * @private
+     * @param {fabric.Object} obj Object that was removed
+     */
+    _onObjectRemoved: function(obj) {
+      // removing active object should fire "selection:cleared" events
+      if (this.getActiveObject() === obj) {
+        this.fire('before:selection:cleared', { target: obj });
+        this._discardActiveObject();
+        this.fire('selection:cleared', { target: obj });
+        obj.fire('deselected');
+      }
+      this.callSuper('_onObjectRemoved', obj);
+    },
+
+    /**
+     * @private
+     */
+    _discardActiveObject: function() {
+      if (this._activeObject) {
+        this._activeObject.set('active', false);
+      }
+      this._activeObject = null;
+    },
+
+    /**
+     * Discards currently active object and fire events
+     * @param {event} e
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    discardActiveObject: function (e) {
+      var activeObject = this._activeObject;
+      this.fire('before:selection:cleared', { target: activeObject, e: e });
+      this._discardActiveObject();
+      this.fire('selection:cleared', { e: e });
+      activeObject && activeObject.fire('deselected', { e: e });
+      return this;
+    },
+
+    /**
+     * @private
+     * @param {fabric.Group} group
+     */
+    _setActiveGroup: function(group) {
+      this._activeGroup = group;
+      if (group) {
+        group.set('active', true);
+      }
+    },
+
+    /**
+     * Sets active group to a specified one
+     * @param {fabric.Group} group Group to set as a current one
+     * @param {Event} e Event object
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    setActiveGroup: function (group, e) {
+      this._setActiveGroup(group);
+      if (group) {
+        this.fire('object:selected', { target: group, e: e });
+        group.fire('selected', { e: e });
+      }
+      return this;
+    },
+
+    /**
+     * Returns currently active group
+     * @return {fabric.Group} Current group
+     */
+    getActiveGroup: function () {
+      return this._activeGroup;
+    },
+
+    /**
+     * @private
+     */
+    _discardActiveGroup: function() {
+      var g = this.getActiveGroup();
+      if (g) {
+        g.destroy();
+      }
+      this.setActiveGroup(null);
+    },
+
+    /**
+     * Discards currently active group and fire events
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    discardActiveGroup: function (e) {
+      var g = this.getActiveGroup();
+      this.fire('before:selection:cleared', { e: e, target: g });
+      this._discardActiveGroup();
+      this.fire('selection:cleared', { e: e });
+      return this;
+    },
+
+    /**
+     * Deactivates all objects on canvas, removing any active group or object
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    deactivateAll: function () {
+      var allObjects = this.getObjects(),
+          i = 0,
+          len = allObjects.length;
+      for ( ; i < len; i++) {
+        allObjects[i].set('active', false);
+      }
+      this._discardActiveGroup();
+      this._discardActiveObject();
+      return this;
+    },
+
+    /**
+     * Deactivates all objects and dispatches appropriate events
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    deactivateAllWithDispatch: function (e) {
+      var activeGroup = this.getActiveGroup(),
+          activeObject = this.getActiveObject();
+      if (activeObject || activeGroup) {
+        this.fire('before:selection:cleared', { target: activeObject || activeGroup, e: e });
+      }
+      this.deactivateAll();
+      if (activeObject || activeGroup) {
+        this.fire('selection:cleared', { e: e, target: activeObject });
+        activeObject && activeObject.fire('deselected');
+      }
+      return this;
+    },
+
+    /**
+     * Clears a canvas element and removes all event listeners
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    dispose: function () {
+      this.callSuper('dispose');
+      var wrapper = this.wrapperEl;
+      this.removeListeners();
+      wrapper.removeChild(this.upperCanvasEl);
+      wrapper.removeChild(this.lowerCanvasEl);
+      delete this.upperCanvasEl;
+      if (wrapper.parentNode) {
+        wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);
+      }
+      delete this.wrapperEl;
+      return this;
+    },
+
+    /**
+     * Clears all contexts (background, main, top) of an instance
+     * @return {fabric.Canvas} thisArg
+     * @chainable
+     */
+    clear: function () {
+      this.discardActiveGroup();
+      this.discardActiveObject();
+      this.clearContext(this.contextTop);
+      return this.callSuper('clear');
+    },
+
+    /**
+     * Draws objects' controls (borders/controls)
+     * @param {CanvasRenderingContext2D} ctx Context to render controls on
+     */
+    drawControls: function(ctx) {
+      var activeGroup = this.getActiveGroup();
+
+      if (activeGroup) {
+        activeGroup._renderControls(ctx);
+      }
+      else {
+        this._drawObjectsControls(ctx);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _drawObjectsControls: function(ctx) {
+      for (var i = 0, len = this._objects.length; i < len; ++i) {
+        if (!this._objects[i] || !this._objects[i].active) {
+          continue;
+        }
+        this._objects[i]._renderControls(ctx);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _toObject: function(instance, methodName, propertiesToInclude) {
+      //If the object is part of the current selection group, it should
+      //be transformed appropriately
+      //i.e. it should be serialised as it would appear if the selection group
+      //were to be destroyed.
+      var originalProperties = this._realizeGroupTransformOnObject(instance),
+          object = this.callSuper('_toObject', instance, methodName, propertiesToInclude);
+      //Undo the damage we did by changing all of its properties
+      this._unwindGroupTransformOnObject(instance, originalProperties);
+      return object;
+    },
+
+    /**
+     * Realises an object's group transformation on it
+     * @private
+     * @param {fabric.Object} [instance] the object to transform (gets mutated)
+     * @returns the original values of instance which were changed
+     */
+    _realizeGroupTransformOnObject: function(instance) {
+      var layoutProps = ['angle', 'flipX', 'flipY', 'height', 'left', 'scaleX', 'scaleY', 'top', 'width'];
+      if (instance.group && instance.group === this.getActiveGroup()) {
+        //Copy all the positionally relevant properties across now
+        var originalValues = {};
+        layoutProps.forEach(function(prop) {
+          originalValues[prop] = instance[prop];
+        });
+        this.getActiveGroup().realizeTransform(instance);
+        return originalValues;
+      }
+      else {
+        return null;
+      }
+    },
+
+    /**
+     * Restores the changed properties of instance
+     * @private
+     * @param {fabric.Object} [instance] the object to un-transform (gets mutated)
+     * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject
+     */
+    _unwindGroupTransformOnObject: function(instance, originalValues) {
+      if (originalValues) {
+        instance.set(originalValues);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _setSVGObject: function(markup, instance, reviver) {
+      var originalProperties;
+      //If the object is in a selection group, simulate what would happen to that
+      //object when the group is deselected
+      originalProperties = this._realizeGroupTransformOnObject(instance);
+      this.callSuper('_setSVGObject', markup, instance, reviver);
+      this._unwindGroupTransformOnObject(instance, originalProperties);
+    },
+  });
+
+  // copying static properties manually to work around Opera's bug,
+  // where "prototype" property is enumerable and overrides existing prototype
+  for (var prop in fabric.StaticCanvas) {
+    if (prop !== 'prototype') {
+      fabric.Canvas[prop] = fabric.StaticCanvas[prop];
+    }
+  }
+
+  if (fabric.isTouchSupported) {
+    /** @ignore */
+    fabric.Canvas.prototype._setCursorFromEvent = function() { };
+  }
+
+  /**
+   * @ignore
+   * @class fabric.Element
+   * @alias fabric.Canvas
+   * @deprecated Use {@link fabric.Canvas} instead.
+   * @constructor
+   */
+  fabric.Element = fabric.Canvas;
+})();
+
+
+(function() {
+
+  var cursorOffset = {
+        mt: 0, // n
+        tr: 1, // ne
+        mr: 2, // e
+        br: 3, // se
+        mb: 4, // s
+        bl: 5, // sw
+        ml: 6, // w
+        tl: 7 // nw
+      },
+      addListener = fabric.util.addListener,
+      removeListener = fabric.util.removeListener;
+
+  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {
+
+    /**
+     * Map of cursor style values for each of the object controls
+     * @private
+     */
+    cursorMap: [
+      'n-resize',
+      'ne-resize',
+      'e-resize',
+      'se-resize',
+      's-resize',
+      'sw-resize',
+      'w-resize',
+      'nw-resize'
+    ],
+
+    /**
+     * Adds mouse listeners to canvas
+     * @private
+     */
+    _initEventListeners: function () {
+
+      this._bindEvents();
+
+      addListener(fabric.window, 'resize', this._onResize);
+
+      // mouse events
+      addListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);
+      addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);
+      addListener(this.upperCanvasEl, 'mouseout', this._onMouseOut);
+      addListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter);
+      addListener(this.upperCanvasEl, 'wheel', this._onMouseWheel);
+      addListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu);
+
+      // touch events
+      addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);
+      addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);
+
+      if (typeof eventjs !== 'undefined' && 'add' in eventjs) {
+        eventjs.add(this.upperCanvasEl, 'gesture', this._onGesture);
+        eventjs.add(this.upperCanvasEl, 'drag', this._onDrag);
+        eventjs.add(this.upperCanvasEl, 'orientation', this._onOrientationChange);
+        eventjs.add(this.upperCanvasEl, 'shake', this._onShake);
+        eventjs.add(this.upperCanvasEl, 'longpress', this._onLongPress);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _bindEvents: function() {
+      this._onMouseDown = this._onMouseDown.bind(this);
+      this._onMouseMove = this._onMouseMove.bind(this);
+      this._onMouseUp = this._onMouseUp.bind(this);
+      this._onResize = this._onResize.bind(this);
+      this._onGesture = this._onGesture.bind(this);
+      this._onDrag = this._onDrag.bind(this);
+      this._onShake = this._onShake.bind(this);
+      this._onLongPress = this._onLongPress.bind(this);
+      this._onOrientationChange = this._onOrientationChange.bind(this);
+      this._onMouseWheel = this._onMouseWheel.bind(this);
+      this._onMouseOut = this._onMouseOut.bind(this);
+      this._onMouseEnter = this._onMouseEnter.bind(this);
+      this._onContextMenu = this._onContextMenu.bind(this);
+    },
+
+    /**
+     * Removes all event listeners
+     */
+    removeListeners: function() {
+      removeListener(fabric.window, 'resize', this._onResize);
+
+      removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);
+      removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);
+      removeListener(this.upperCanvasEl, 'mouseout', this._onMouseOut);
+      removeListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter);
+      removeListener(this.upperCanvasEl, 'wheel', this._onMouseWheel);
+      removeListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu);
+
+      removeListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);
+      removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);
+
+      if (typeof eventjs !== 'undefined' && 'remove' in eventjs) {
+        eventjs.remove(this.upperCanvasEl, 'gesture', this._onGesture);
+        eventjs.remove(this.upperCanvasEl, 'drag', this._onDrag);
+        eventjs.remove(this.upperCanvasEl, 'orientation', this._onOrientationChange);
+        eventjs.remove(this.upperCanvasEl, 'shake', this._onShake);
+        eventjs.remove(this.upperCanvasEl, 'longpress', this._onLongPress);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on Event.js gesture
+     * @param {Event} [self] Inner Event object
+     */
+    _onGesture: function(e, self) {
+      this.__onTransformGesture && this.__onTransformGesture(e, self);
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on Event.js drag
+     * @param {Event} [self] Inner Event object
+     */
+    _onDrag: function(e, self) {
+      this.__onDrag && this.__onDrag(e, self);
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on wheel event
+     */
+    _onMouseWheel: function(e) {
+      this.__onMouseWheel(e);
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousedown
+     */
+    _onMouseOut: function(e) {
+      var target = this._hoveredTarget;
+      this.fire('mouse:out', { target: target, e: e });
+      this._hoveredTarget = null;
+      target && target.fire('mouseout', { e: e });
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mouseenter
+     */
+    _onMouseEnter: function(e) {
+      if (!this.findTarget(e)) {
+        this.fire('mouse:over', { target: null, e: e });
+        this._hoveredTarget = null;
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on Event.js orientation change
+     * @param {Event} [self] Inner Event object
+     */
+    _onOrientationChange: function(e, self) {
+      this.__onOrientationChange && this.__onOrientationChange(e, self);
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on Event.js shake
+     * @param {Event} [self] Inner Event object
+     */
+    _onShake: function(e, self) {
+      this.__onShake && this.__onShake(e, self);
+    },
+
+    /**
+     * @private
+     * @param {Event} [e] Event object fired on Event.js shake
+     * @param {Event} [self] Inner Event object
+     */
+    _onLongPress: function(e, self) {
+      this.__onLongPress && this.__onLongPress(e, self);
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousedown
+     */
+    _onContextMenu: function (e) {
+      if (this.stopContextMenu) {
+        e.stopPropagation()
+        e.preventDefault();
+      }
+      return false;
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousedown
+     */
+    _onMouseDown: function (e) {
+      this.__onMouseDown(e);
+
+      addListener(fabric.document, 'touchend', this._onMouseUp);
+      addListener(fabric.document, 'touchmove', this._onMouseMove);
+
+      removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);
+      removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);
+
+      if (e.type === 'touchstart') {
+        // Unbind mousedown to prevent double triggers from touch devices
+        removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);
+      }
+      else {
+        addListener(fabric.document, 'mouseup', this._onMouseUp);
+        addListener(fabric.document, 'mousemove', this._onMouseMove);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mouseup
+     */
+    _onMouseUp: function (e) {
+      this.__onMouseUp(e);
+
+      removeListener(fabric.document, 'mouseup', this._onMouseUp);
+      removeListener(fabric.document, 'touchend', this._onMouseUp);
+
+      removeListener(fabric.document, 'mousemove', this._onMouseMove);
+      removeListener(fabric.document, 'touchmove', this._onMouseMove);
+
+      addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);
+      addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);
+
+      if (e.type === 'touchend') {
+        // Wait 400ms before rebinding mousedown to prevent double triggers
+        // from touch devices
+        var _this = this;
+        setTimeout(function() {
+          addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown);
+        }, 400);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousemove
+     */
+    _onMouseMove: function (e) {
+      !this.allowTouchScrolling && e.preventDefault && e.preventDefault();
+      this.__onMouseMove(e);
+    },
+
+    /**
+     * @private
+     */
+    _onResize: function () {
+      this.calcOffset();
+    },
+
+    /**
+     * Decides whether the canvas should be redrawn in mouseup and mousedown events.
+     * @private
+     * @param {Object} target
+     * @param {Object} pointer
+     */
+    _shouldRender: function(target, pointer) {
+      var activeObject = this.getActiveGroup() || this.getActiveObject();
+
+      return !!(
+        (target && (
+          target.isMoving ||
+          target !== activeObject))
+        ||
+        (!target && !!activeObject)
+        ||
+        (!target && !activeObject && !this._groupSelector)
+        ||
+        (pointer &&
+          this._previousPointer &&
+          this.selection && (
+          pointer.x !== this._previousPointer.x ||
+          pointer.y !== this._previousPointer.y))
+      );
+    },
+
+    /**
+     * Method that defines the actions when mouse is released on canvas.
+     * The method resets the currentTransform parameters, store the image corner
+     * position in the image object and render the canvas on top.
+     * @private
+     * @param {Event} e Event object fired on mouseup
+     */
+    __onMouseUp: function (e) {
+      var target, searchTarget = true, transform = this._currentTransform,
+          groupSelector = this._groupSelector,
+          isClick = (!groupSelector || (groupSelector.left === 0 && groupSelector.top === 0));
+
+      if (this.isDrawingMode && this._isCurrentlyDrawing) {
+        this._onMouseUpInDrawingMode(e);
+        return;
+      }
+
+      if (transform) {
+        this._finalizeCurrentTransform();
+        searchTarget = !transform.actionPerformed;
+      }
+
+      target = searchTarget ? this.findTarget(e, true) : transform.target;
+
+      var shouldRender = this._shouldRender(target, this.getPointer(e));
+
+      if (target || !isClick) {
+        this._maybeGroupObjects(e);
+      }
+      else {
+        // those are done by default on mouse up
+        // by _maybeGroupObjects, we are skipping it in case of no target find
+        this._groupSelector = null;
+        this._currentTransform = null;
+      }
+
+      if (target) {
+        target.isMoving = false;
+      }
+
+      this._handleCursorAndEvent(e, target, 'up');
+      target && (target.__corner = 0);
+      shouldRender && this.renderAll();
+    },
+
+    /**
+     * set cursor for mouse up and handle mouseUp event
+     * @param {Event} e event from mouse
+     * @param {fabric.Object} target receiving event
+     * @param {String} eventType event to fire (up, down or move)
+     */
+    _handleCursorAndEvent: function(e, target, eventType) {
+      this._setCursorFromEvent(e, target);
+      this._handleEvent(e, eventType, target ? target : null);
+    },
+
+    /**
+     * Handle event firing for target and subtargets
+     * @param {Event} e event from mouse
+     * @param {String} eventType event to fire (up, down or move)
+     * @param {fabric.Object} targetObj receiving event
+     */
+    _handleEvent: function(e, eventType, targetObj) {
+      var target = typeof targetObj === undefined ? this.findTarget(e) : targetObj,
+          targets = this.targets || [],
+          options = { e: e, target: target, subTargets: targets };
+
+      this.fire('mouse:' + eventType, options);
+      target && target.fire('mouse' + eventType, options);
+      for (var i = 0; i < targets.length; i++) {
+        targets[i].fire('mouse' + eventType, options);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _finalizeCurrentTransform: function() {
+
+      var transform = this._currentTransform,
+          target = transform.target;
+
+      if (target._scaling) {
+        target._scaling = false;
+      }
+
+      target.setCoords();
+      this._restoreOriginXY(target);
+
+      if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {
+        this.fire('object:modified', { target: target });
+        target.fire('modified');
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} target Object to restore
+     */
+    _restoreOriginXY: function(target) {
+      if (this._previousOriginX && this._previousOriginY) {
+
+        var originPoint = target.translateToOriginPoint(
+          target.getCenterPoint(),
+          this._previousOriginX,
+          this._previousOriginY);
+
+        target.originX = this._previousOriginX;
+        target.originY = this._previousOriginY;
+
+        target.left = originPoint.x;
+        target.top = originPoint.y;
+
+        this._previousOriginX = null;
+        this._previousOriginY = null;
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousedown
+     */
+    _onMouseDownInDrawingMode: function(e) {
+      this._isCurrentlyDrawing = true;
+      this.discardActiveObject(e).renderAll();
+      if (this.clipTo) {
+        fabric.util.clipContext(this, this.contextTop);
+      }
+      var pointer = this.getPointer(e);
+      this.freeDrawingBrush.onMouseDown(pointer);
+      this._handleEvent(e, 'down');
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mousemove
+     */
+    _onMouseMoveInDrawingMode: function(e) {
+      if (this._isCurrentlyDrawing) {
+        var pointer = this.getPointer(e);
+        this.freeDrawingBrush.onMouseMove(pointer);
+      }
+      this.setCursor(this.freeDrawingCursor);
+      this._handleEvent(e, 'move');
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object fired on mouseup
+     */
+    _onMouseUpInDrawingMode: function(e) {
+      this._isCurrentlyDrawing = false;
+      if (this.clipTo) {
+        this.contextTop.restore();
+      }
+      this.freeDrawingBrush.onMouseUp();
+      this._handleEvent(e, 'up');
+    },
+
+    /**
+     * Method that defines the actions when mouse is clic ked on canvas.
+     * The method inits the currentTransform parameters and renders all the
+     * canvas so the current image can be placed on the top canvas and the rest
+     * in on the container one.
+     * @private
+     * @param {Event} e Event object fired on mousedown
+     */
+    __onMouseDown: function (e) {
+
+      var target = this.findTarget(e),
+          pointer = this.getPointer(e, true);
+
+      // if right click just fire events
+      var isRightClick  = 'which' in e ? e.which === 3 : e.button === 2;
+      if (isRightClick) {
+        if (this.fireRightClick) {
+          this._handleEvent(e, 'down', target ? target : null);
+        }
+        return;
+      }
+
+      if (this.isDrawingMode) {
+        this._onMouseDownInDrawingMode(e);
+        return;
+      }
+
+      // ignore if some object is being transformed at this moment
+      if (this._currentTransform) {
+        return;
+      }
+
+      // save pointer for check in __onMouseUp event
+      this._previousPointer = pointer;
+
+      var shouldRender = this._shouldRender(target, pointer),
+          shouldGroup = this._shouldGroup(e, target);
+
+      if (this._shouldClearSelection(e, target)) {
+        this._clearSelection(e, target, pointer);
+      }
+      else if (shouldGroup) {
+        this._handleGrouping(e, target);
+        target = this.getActiveGroup();
+      }
+
+      if (target) {
+        if (target.selectable && (target.__corner || !shouldGroup)) {
+          this._beforeTransform(e, target);
+          this._setupCurrentTransform(e, target);
+        }
+
+        if (target !== this.getActiveGroup() && target !== this.getActiveObject()) {
+          this.deactivateAll();
+          target.selectable && this.setActiveObject(target, e);
+        }
+      }
+      this._handleEvent(e, 'down', target ? target : null);
+      // we must renderAll so that we update the visuals
+      shouldRender && this.renderAll();
+    },
+
+    /**
+     * @private
+     */
+    _beforeTransform: function(e, target) {
+      this.stateful && target.saveState();
+
+      // determine if it's a drag or rotate case
+      if (target._findTargetCorner(this.getPointer(e))) {
+        this.onBeforeScaleRotate(target);
+      }
+
+    },
+
+    /**
+     * @private
+     */
+    _clearSelection: function(e, target, pointer) {
+      this.deactivateAllWithDispatch(e);
+
+      if (target && target.selectable) {
+        this.setActiveObject(target, e);
+      }
+      else if (this.selection) {
+        this._groupSelector = {
+          ex: pointer.x,
+          ey: pointer.y,
+          top: 0,
+          left: 0
+        };
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} target Object for that origin is set to center
+     */
+    _setOriginToCenter: function(target) {
+      this._previousOriginX = this._currentTransform.target.originX;
+      this._previousOriginY = this._currentTransform.target.originY;
+
+      var center = target.getCenterPoint();
+
+      target.originX = 'center';
+      target.originY = 'center';
+
+      target.left = center.x;
+      target.top = center.y;
+
+      this._currentTransform.left = target.left;
+      this._currentTransform.top = target.top;
+    },
+
+    /**
+     * @private
+     * @param {Object} target Object for that center is set to origin
+     */
+    _setCenterToOrigin: function(target) {
+      var originPoint = target.translateToOriginPoint(
+        target.getCenterPoint(),
+        this._previousOriginX,
+        this._previousOriginY);
+
+      target.originX = this._previousOriginX;
+      target.originY = this._previousOriginY;
+
+      target.left = originPoint.x;
+      target.top = originPoint.y;
+
+      this._previousOriginX = null;
+      this._previousOriginY = null;
+    },
+
+    /**
+     * Method that defines the actions when mouse is hovering the canvas.
+     * The currentTransform parameter will definde whether the user is rotating/scaling/translating
+     * an image or neither of them (only hovering). A group selection is also possible and would cancel
+     * all any other type of action.
+     * In case of an image transformation only the top canvas will be rendered.
+     * @private
+     * @param {Event} e Event object fired on mousemove
+     */
+    __onMouseMove: function (e) {
+
+      var target, pointer;
+
+      if (this.isDrawingMode) {
+        this._onMouseMoveInDrawingMode(e);
+        return;
+      }
+      if (typeof e.touches !== 'undefined' && e.touches.length > 1) {
+        return;
+      }
+
+      var groupSelector = this._groupSelector;
+
+      // We initially clicked in an empty area, so we draw a box for multiple selection
+      if (groupSelector) {
+        pointer = this.getPointer(e, true);
+
+        groupSelector.left = pointer.x - groupSelector.ex;
+        groupSelector.top = pointer.y - groupSelector.ey;
+
+        this.renderTop();
+      }
+      else if (!this._currentTransform) {
+        target = this.findTarget(e);
+        this._setCursorFromEvent(e, target);
+      }
+      else {
+        this._transformObject(e);
+      }
+      this._handleEvent(e, 'move', target ? target : null);
+    },
+
+    /**
+     * Method that defines actions when an Event Mouse Wheel
+     * @param {Event} e Event object fired on mouseup
+     */
+    __onMouseWheel: function(e) {
+      this.fire('mouse:wheel', {
+        e: e
+      });
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event fired on mousemove
+     */
+    _transformObject: function(e) {
+      var pointer = this.getPointer(e),
+          transform = this._currentTransform;
+
+      transform.reset = false;
+      transform.target.isMoving = true;
+
+      this._beforeScaleTransform(e, transform);
+      this._performTransformAction(e, transform, pointer);
+
+      transform.actionPerformed && this.renderAll();
+    },
+
+    /**
+     * @private
+     */
+    _performTransformAction: function(e, transform, pointer) {
+      var x = pointer.x,
+          y = pointer.y,
+          target = transform.target,
+          action = transform.action,
+          actionPerformed = false;
+
+      if (action === 'rotate') {
+        (actionPerformed = this._rotateObject(x, y)) && this._fire('rotating', target, e);
+      }
+      else if (action === 'scale') {
+        (actionPerformed = this._onScale(e, transform, x, y)) && this._fire('scaling', target, e);
+      }
+      else if (action === 'scaleX') {
+        (actionPerformed = this._scaleObject(x, y, 'x')) && this._fire('scaling', target, e);
+      }
+      else if (action === 'scaleY') {
+        (actionPerformed = this._scaleObject(x, y, 'y')) && this._fire('scaling', target, e);
+      }
+      else if (action === 'skewX') {
+        (actionPerformed = this._skewObject(x, y, 'x')) && this._fire('skewing', target, e);
+      }
+      else if (action === 'skewY') {
+        (actionPerformed = this._skewObject(x, y, 'y')) && this._fire('skewing', target, e);
+      }
+      else {
+        actionPerformed = this._translateObject(x, y);
+        if (actionPerformed) {
+          this._fire('moving', target, e);
+          this.setCursor(target.moveCursor || this.moveCursor);
+        }
+      }
+      transform.actionPerformed = actionPerformed;
+    },
+
+    /**
+     * @private
+     */
+    _fire: function(eventName, target, e) {
+      this.fire('object:' + eventName, { target: target, e: e });
+      target.fire(eventName, { e: e });
+    },
+
+    /**
+     * @private
+     */
+    _beforeScaleTransform: function(e, transform) {
+      if (transform.action === 'scale' || transform.action === 'scaleX' || transform.action === 'scaleY') {
+        var centerTransform = this._shouldCenterTransform(transform.target);
+
+        // Switch from a normal resize to center-based
+        if ((centerTransform && (transform.originX !== 'center' || transform.originY !== 'center')) ||
+           // Switch from center-based resize to normal one
+           (!centerTransform && transform.originX === 'center' && transform.originY === 'center')
+        ) {
+          this._resetCurrentTransform();
+          transform.reset = true;
+        }
+      }
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object
+     * @param {Object} transform current tranform
+     * @param {Number} x mouse position x from origin
+     * @param {Number} y mouse poistion y from origin
+     * @return {Boolean} true if the scaling occurred
+     */
+    _onScale: function(e, transform, x, y) {
+      if ((e[this.uniScaleKey] || this.uniScaleTransform) && !transform.target.get('lockUniScaling')) {
+        transform.currentAction = 'scale';
+        return this._scaleObject(x, y);
+      }
+      else {
+        // Switch from a normal resize to proportional
+        if (!transform.reset && transform.currentAction === 'scale') {
+          this._resetCurrentTransform();
+        }
+
+        transform.currentAction = 'scaleEqually';
+        return this._scaleObject(x, y, 'equally');
+      }
+    },
+
+    /**
+     * Sets the cursor depending on where the canvas is being hovered.
+     * Note: very buggy in Opera
+     * @param {Event} e Event object
+     * @param {Object} target Object that the mouse is hovering, if so.
+     */
+    _setCursorFromEvent: function (e, target) {
+      if (!target) {
+        this.setCursor(this.defaultCursor);
+        return false;
+      }
+
+      var hoverCursor = target.hoverCursor || this.hoverCursor;
+      if (!target.selectable) {
+        //let's skip _findTargetCorner if object is not selectable
+        this.setCursor(hoverCursor);
+      }
+      else {
+        var activeGroup = this.getActiveGroup(),
+            // only show proper corner when group selection is not active
+            corner = target._findTargetCorner
+                      && (!activeGroup || !activeGroup.contains(target))
+                      && target._findTargetCorner(this.getPointer(e, true));
+
+        if (!corner) {
+          this.setCursor(hoverCursor);
+        }
+        else {
+          this._setCornerCursor(corner, target, e);
+        }
+      }
+      //actually unclear why it should return something
+      //is never evaluated
+      return true;
+    },
+
+    /**
+     * @private
+     */
+    _setCornerCursor: function(corner, target, e) {
+      if (corner in cursorOffset) {
+        this.setCursor(this._getRotatedCornerCursor(corner, target, e));
+      }
+      else if (corner === 'mtr' && target.hasRotatingPoint) {
+        this.setCursor(this.rotationCursor);
+      }
+      else {
+        this.setCursor(this.defaultCursor);
+        return false;
+      }
+    },
+
+    /**
+     * @private
+     */
+    _getRotatedCornerCursor: function(corner, target, e) {
+      var n = Math.round((target.getAngle() % 360) / 45);
+
+      if (n < 0) {
+        n += 8; // full circle ahead
+      }
+      n += cursorOffset[corner];
+      if (e[this.altActionKey] && cursorOffset[corner] % 2 === 0) {
+        //if we are holding shift and we are on a mx corner...
+        n += 2;
+      }
+      // normalize n to be from 0 to 7
+      n %= 8;
+
+      return this.cursorMap[n];
+    }
+  });
+})();
+
+
+(function() {
+
+  var min = Math.min,
+      max = Math.max;
+
+  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {
+
+    /**
+     * @private
+     * @param {Event} e Event object
+     * @param {fabric.Object} target
+     * @return {Boolean}
+     */
+    _shouldGroup: function(e, target) {
+      var activeObject = this.getActiveObject();
+      return e[this.selectionKey] && target && target.selectable &&
+            (this.getActiveGroup() || (activeObject && activeObject !== target))
+            && this.selection;
+    },
+
+    /**
+     * @private
+     * @param {Event} e Event object
+     * @param {fabric.Object} target
+     */
+    _handleGrouping: function (e, target) {
+      var activeGroup = this.getActiveGroup();
+
+      if (target === activeGroup) {
+        // if it's a group, find target again, using activeGroup objects
+        target = this.findTarget(e, true);
+        // if even object is not found, bail out
+        if (!target) {
+          return;
+        }
+      }
+      if (activeGroup) {
+        this._updateActiveGroup(target, e);
+      }
+      else {
+        this._createActiveGroup(target, e);
+      }
+
+      if (this._activeGroup) {
+        this._activeGroup.saveCoords();
+      }
+    },
+
+    /**
+     * @private
+     */
+    _updateActiveGroup: function(target, e) {
+      var activeGroup = this.getActiveGroup();
+
+      if (activeGroup.contains(target)) {
+
+        activeGroup.removeWithUpdate(target);
+        target.set('active', false);
+
+        if (activeGroup.size() === 1) {
+          // remove group alltogether if after removal it only contains 1 object
+          this.discardActiveGroup(e);
+          // activate last remaining object
+          this.setActiveObject(activeGroup.item(0));
+          return;
+        }
+      }
+      else {
+        activeGroup.addWithUpdate(target);
+      }
+      this.fire('selection:created', { target: activeGroup, e: e });
+      activeGroup.set('active', true);
+    },
+
+    /**
+     * @private
+     */
+    _createActiveGroup: function(target, e) {
+
+      if (this._activeObject && target !== this._activeObject) {
+
+        var group = this._createGroup(target);
+        group.addWithUpdate();
+
+        this.setActiveGroup(group);
+        this._activeObject = null;
+
+        this.fire('selection:created', { target: group, e: e });
+      }
+
+      target.set('active', true);
+    },
+
+    /**
+     * @private
+     * @param {Object} target
+     */
+    _createGroup: function(target) {
+
+      var objects = this.getObjects(),
+          isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),
+          groupObjects = isActiveLower
+            ? [this._activeObject, target]
+            : [target, this._activeObject];
+      this._activeObject.isEditing && this._activeObject.exitEditing();
+      return new fabric.Group(groupObjects, {
+        canvas: this
+      });
+    },
+
+    /**
+     * @private
+     * @param {Event} e mouse event
+     */
+    _groupSelectedObjects: function (e) {
+
+      var group = this._collectObjects();
+
+      // do not create group for 1 element only
+      if (group.length === 1) {
+        this.setActiveObject(group[0], e);
+      }
+      else if (group.length > 1) {
+        group = new fabric.Group(group.reverse(), {
+          canvas: this
+        });
+        group.addWithUpdate();
+        this.setActiveGroup(group, e);
+        group.saveCoords();
+        this.fire('selection:created', { target: group });
+        this.renderAll();
+      }
+    },
+
+    /**
+     * @private
+     */
+    _collectObjects: function() {
+      var group = [],
+          currentObject,
+          x1 = this._groupSelector.ex,
+          y1 = this._groupSelector.ey,
+          x2 = x1 + this._groupSelector.left,
+          y2 = y1 + this._groupSelector.top,
+          selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),
+          selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),
+          isClick = x1 === x2 && y1 === y2;
+
+      for (var i = this._objects.length; i--; ) {
+        currentObject = this._objects[i];
+
+        if (!currentObject || !currentObject.selectable || !currentObject.visible) {
+          continue;
+        }
+
+        if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||
+            currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||
+            currentObject.containsPoint(selectionX1Y1) ||
+            currentObject.containsPoint(selectionX2Y2)
+        ) {
+          currentObject.set('active', true);
+          group.push(currentObject);
+
+          // only add one object if it's a click
+          if (isClick) {
+            break;
+          }
+        }
+      }
+
+      return group;
+    },
+
+    /**
+     * @private
+     */
+    _maybeGroupObjects: function(e) {
+      if (this.selection && this._groupSelector) {
+        this._groupSelectedObjects(e);
+      }
+
+      var activeGroup = this.getActiveGroup();
+      if (activeGroup) {
+        activeGroup.setObjectsCoords().setCoords();
+        activeGroup.isMoving = false;
+        this.setCursor(this.defaultCursor);
+      }
+
+      // clear selection and current transformation
+      this._groupSelector = null;
+      this._currentTransform = null;
+    }
+  });
+
+})();
+
+
+(function () {
+
+  var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality');
+
+  fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
+
+    /**
+     * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately
+     * @param {Object} [options] Options object
+     * @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
+     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
+     * @param {Number} [options.multiplier=1] Multiplier to scale by
+     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
+     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
+     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14
+     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14
+     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
+     * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}
+     * @example <caption>Generate jpeg dataURL with lower quality</caption>
+     * var dataURL = canvas.toDataURL({
+     *   format: 'jpeg',
+     *   quality: 0.8
+     * });
+     * @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>
+     * var dataURL = canvas.toDataURL({
+     *   format: 'png',
+     *   left: 100,
+     *   top: 100,
+     *   width: 200,
+     *   height: 200
+     * });
+     * @example <caption>Generate double scaled png dataURL</caption>
+     * var dataURL = canvas.toDataURL({
+     *   format: 'png',
+     *   multiplier: 2
+     * });
+     */
+    toDataURL: function (options) {
+      options || (options = { });
+
+      var format = options.format || 'png',
+          quality = options.quality || 1,
+          multiplier = options.multiplier || 1,
+          cropping = {
+            left: options.left || 0,
+            top: options.top || 0,
+            width: options.width || 0,
+            height: options.height || 0,
+          };
+      return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier);
+    },
+
+    /**
+     * @private
+     */
+    __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {
+
+      var origWidth = this.getWidth(),
+          origHeight = this.getHeight(),
+          scaledWidth = (cropping.width || this.getWidth()) * multiplier,
+          scaledHeight = (cropping.height || this.getHeight()) * multiplier,
+          zoom = this.getZoom(),
+          newZoom = zoom * multiplier,
+          vp = this.viewportTransform,
+          translateX = (vp[4] - cropping.left) * multiplier,
+          translateY = (vp[5] - cropping.top) * multiplier,
+          newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
+          originalInteractive = this.interactive;
+
+      this.viewportTransform = newVp;
+      // setting interactive to false avoid exporting controls
+      this.interactive && (this.interactive = false);
+      if (origWidth !== scaledWidth || origHeight !== scaledHeight) {
+        // this.setDimensions is going to renderAll also;
+        this.setDimensions({ width: scaledWidth, height: scaledHeight });
+      }
+      else {
+        this.renderAll();
+      }
+      var data = this.__toDataURL(format, quality, cropping);
+      originalInteractive && (this.interactive = originalInteractive);
+      this.viewportTransform = vp;
+      //setDimensions with no option object is taking care of:
+      //this.width, this.height, this.renderAll()
+      this.setDimensions({ width: origWidth, height: origHeight });
+      return data;
+    },
+
+    /**
+     * @private
+     */
+    __toDataURL: function(format, quality) {
+
+      var canvasEl = this.contextContainer.canvas;
+      // to avoid common confusion https://github.com/kangax/fabric.js/issues/806
+      if (format === 'jpg') {
+        format = 'jpeg';
+      }
+
+      var data = supportQuality
+                ? canvasEl.toDataURL('image/' + format, quality)
+                : canvasEl.toDataURL('image/' + format);
+
+      return data;
+    },
+
+    /**
+     * Exports canvas element to a dataurl image (allowing to change image size via multiplier).
+     * @deprecated since 1.0.13
+     * @param {String} format (png|jpeg)
+     * @param {Number} multiplier
+     * @param {Number} quality (0..1)
+     * @return {String}
+     */
+    toDataURLWithMultiplier: function (format, multiplier, quality) {
+      return this.toDataURL({
+        format: format,
+        multiplier: multiplier,
+        quality: quality
+      });
+    },
+  });
+
+})();
+
+
+fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
+
+  /**
+   * Populates canvas with data from the specified dataless JSON.
+   * JSON format must conform to the one of {@link fabric.Canvas#toDatalessJSON}
+   * @deprecated since 1.2.2
+   * @param {String|Object} json JSON string or object
+   * @param {Function} callback Callback, invoked when json is parsed
+   *                            and corresponding objects (e.g: {@link fabric.Image})
+   *                            are initialized
+   * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.
+   * @return {fabric.Canvas} instance
+   * @chainable
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}
+   */
+  loadFromDatalessJSON: function (json, callback, reviver) {
+    return this.loadFromJSON(json, callback, reviver);
+  },
+
+  /**
+   * Populates canvas with data from the specified JSON.
+   * JSON format must conform to the one of {@link fabric.Canvas#toJSON}
+   * @param {String|Object} json JSON string or object
+   * @param {Function} callback Callback, invoked when json is parsed
+   *                            and corresponding objects (e.g: {@link fabric.Image})
+   *                            are initialized
+   * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.
+   * @return {fabric.Canvas} instance
+   * @chainable
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}
+   * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo}
+   * @example <caption>loadFromJSON</caption>
+   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));
+   * @example <caption>loadFromJSON with reviver</caption>
+   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {
+   *   // `o` = json object
+   *   // `object` = fabric.Object instance
+   *   // ... do some stuff ...
+   * });
+   */
+  loadFromJSON: function (json, callback, reviver) {
+    if (!json) {
+      return;
+    }
+
+    // serialize if it wasn't already
+    var serialized = (typeof json === 'string')
+      ? JSON.parse(json)
+      : fabric.util.object.clone(json);
+
+    this.clear();
+
+    var _this = this;
+    this._enlivenObjects(serialized.objects, function () {
+      _this._setBgOverlay(serialized, function () {
+        // remove parts i cannot set as options
+        delete serialized.objects;
+        delete serialized.backgroundImage;
+        delete serialized.overlayImage;
+        delete serialized.background;
+        delete serialized.overlay;
+        // this._initOptions does too many things to just
+        // call it. Normally loading an Object from JSON
+        // create the Object instance. Here the Canvas is
+        // already an instance and we are just loading things over it
+        for (var prop in serialized) {
+          _this[prop] = serialized[prop];
+        }
+        callback && callback();
+      });
+    }, reviver);
+    return this;
+  },
+
+  /**
+   * @private
+   * @param {Object} serialized Object with background and overlay information
+   * @param {Function} callback Invoked after all background and overlay images/patterns loaded
+   */
+  _setBgOverlay: function(serialized, callback) {
+    var _this = this,
+        loaded = {
+          backgroundColor: false,
+          overlayColor: false,
+          backgroundImage: false,
+          overlayImage: false
+        };
+
+    if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) {
+      callback && callback();
+      return;
+    }
+
+    var cbIfLoaded = function () {
+      if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) {
+        _this.renderAll();
+        callback && callback();
+      }
+    };
+
+    this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded);
+    this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded);
+    this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded);
+    this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded);
+
+    cbIfLoaded();
+  },
+
+  /**
+   * @private
+   * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor)
+   * @param {(Object|String)} value Value to set
+   * @param {Object} loaded Set loaded property to true if property is set
+   * @param {Object} callback Callback function to invoke after property is set
+   */
+  __setBgOverlay: function(property, value, loaded, callback) {
+    var _this = this;
+
+    if (!value) {
+      loaded[property] = true;
+      return;
+    }
+
+    if (property === 'backgroundImage' || property === 'overlayImage') {
+      fabric.Image.fromObject(value, function(img) {
+        _this[property] = img;
+        loaded[property] = true;
+        callback && callback();
+      });
+    }
+    else {
+      this['set' + fabric.util.string.capitalize(property, true)](value, function() {
+        loaded[property] = true;
+        callback && callback();
+      });
+    }
+  },
+
+  /**
+   * @private
+   * @param {Array} objects
+   * @param {Function} callback
+   * @param {Function} [reviver]
+   */
+  _enlivenObjects: function (objects, callback, reviver) {
+    var _this = this;
+
+    if (!objects || objects.length === 0) {
+      callback && callback();
+      return;
+    }
+
+    var renderOnAddRemove = this.renderOnAddRemove;
+    this.renderOnAddRemove = false;
+
+    fabric.util.enlivenObjects(objects, function(enlivenedObjects) {
+      enlivenedObjects.forEach(function(obj, index) {
+        // we splice the array just in case some custom classes restored from JSON
+        // will add more object to canvas at canvas init.
+        _this.insertAt(obj, index);
+      });
+
+      _this.renderOnAddRemove = renderOnAddRemove;
+      callback && callback();
+    }, null, reviver);
+  },
+
+  /**
+   * @private
+   * @param {String} format
+   * @param {Function} callback
+   */
+  _toDataURL: function (format, callback) {
+    this.clone(function (clone) {
+      callback(clone.toDataURL(format));
+    });
+  },
+
+  /**
+   * @private
+   * @param {String} format
+   * @param {Number} multiplier
+   * @param {Function} callback
+   */
+  _toDataURLWithMultiplier: function (format, multiplier, callback) {
+    this.clone(function (clone) {
+      callback(clone.toDataURLWithMultiplier(format, multiplier));
+    });
+  },
+
+  /**
+   * Clones canvas instance
+   * @param {Object} [callback] Receives cloned instance as a first argument
+   * @param {Array} [properties] Array of properties to include in the cloned canvas and children
+   */
+  clone: function (callback, properties) {
+    var data = JSON.stringify(this.toJSON(properties));
+    this.cloneWithoutData(function(clone) {
+      clone.loadFromJSON(data, function() {
+        callback && callback(clone);
+      });
+    });
+  },
+
+  /**
+   * Clones canvas instance without cloning existing data.
+   * This essentially copies canvas dimensions, clipping properties, etc.
+   * but leaves data empty (so that you can populate it with your own)
+   * @param {Object} [callback] Receives cloned instance as a first argument
+   */
+  cloneWithoutData: function(callback) {
+    var el = fabric.document.createElement('canvas');
+
+    el.width = this.getWidth();
+    el.height = this.getHeight();
+
+    var clone = new fabric.Canvas(el);
+    clone.clipTo = this.clipTo;
+    if (this.backgroundImage) {
+      clone.setBackgroundImage(this.backgroundImage.src, function() {
+        clone.renderAll();
+        callback && callback(clone);
+      });
+      clone.backgroundImageOpacity = this.backgroundImageOpacity;
+      clone.backgroundImageStretch = this.backgroundImageStretch;
+    }
+    else {
+      callback && callback(clone);
+    }
+  }
+});
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      toFixed = fabric.util.toFixed,
+      capitalize = fabric.util.string.capitalize,
+      degreesToRadians = fabric.util.degreesToRadians,
+      supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
+
+  if (fabric.Object) {
+    return;
+  }
+
+  /**
+   * Root object class from which all 2d shape classes inherit from
+   * @class fabric.Object
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#objects}
+   * @see {@link fabric.Object#initialize} for constructor definition
+   *
+   * @fires added
+   * @fires removed
+   *
+   * @fires selected
+   * @fires deselected
+   * @fires modified
+   * @fires rotating
+   * @fires scaling
+   * @fires moving
+   * @fires skewing
+   *
+   * @fires mousedown
+   * @fires mouseup
+   * @fires mouseover
+   * @fires mouseout
+   */
+  fabric.Object = fabric.util.createClass(/** @lends fabric.Object.prototype */ {
+
+    /**
+     * Retrieves object's {@link fabric.Object#clipTo|clipping function}
+     * @method getClipTo
+     * @memberOf fabric.Object.prototype
+     * @return {Function}
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#clipTo|clipping function}
+     * @method setClipTo
+     * @memberOf fabric.Object.prototype
+     * @param {Function} clipTo Clipping function
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#transformMatrix|transformMatrix}
+     * @method getTransformMatrix
+     * @memberOf fabric.Object.prototype
+     * @return {Array} transformMatrix
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#transformMatrix|transformMatrix}
+     * @method setTransformMatrix
+     * @memberOf fabric.Object.prototype
+     * @param {Array} transformMatrix
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#visible|visible} state
+     * @method getVisible
+     * @memberOf fabric.Object.prototype
+     * @return {Boolean} True if visible
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#visible|visible} state
+     * @method setVisible
+     * @memberOf fabric.Object.prototype
+     * @param {Boolean} value visible value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#shadow|shadow}
+     * @method getShadow
+     * @memberOf fabric.Object.prototype
+     * @return {Object} Shadow instance
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#stroke|stroke}
+     * @method getStroke
+     * @memberOf fabric.Object.prototype
+     * @return {String} stroke value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#stroke|stroke}
+     * @method setStroke
+     * @memberOf fabric.Object.prototype
+     * @param {String} value stroke value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#strokeWidth|strokeWidth}
+     * @method getStrokeWidth
+     * @memberOf fabric.Object.prototype
+     * @return {Number} strokeWidth value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#strokeWidth|strokeWidth}
+     * @method setStrokeWidth
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value strokeWidth value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#originX|originX}
+     * @method getOriginX
+     * @memberOf fabric.Object.prototype
+     * @return {String} originX value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#originX|originX}
+     * @method setOriginX
+     * @memberOf fabric.Object.prototype
+     * @param {String} value originX value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#originY|originY}
+     * @method getOriginY
+     * @memberOf fabric.Object.prototype
+     * @return {String} originY value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#originY|originY}
+     * @method setOriginY
+     * @memberOf fabric.Object.prototype
+     * @param {String} value originY value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#fill|fill}
+     * @method getFill
+     * @memberOf fabric.Object.prototype
+     * @return {String} Fill value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#fill|fill}
+     * @method setFill
+     * @memberOf fabric.Object.prototype
+     * @param {String} value Fill value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#opacity|opacity}
+     * @method getOpacity
+     * @memberOf fabric.Object.prototype
+     * @return {Number} Opacity value (0-1)
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#opacity|opacity}
+     * @method setOpacity
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value Opacity value (0-1)
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#angle|angle} (in degrees)
+     * @method getAngle
+     * @memberOf fabric.Object.prototype
+     * @return {Number}
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#top|top position}
+     * @method getTop
+     * @memberOf fabric.Object.prototype
+     * @return {Number} Top value (in pixels)
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#top|top position}
+     * @method setTop
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value Top value (in pixels)
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#left|left position}
+     * @method getLeft
+     * @memberOf fabric.Object.prototype
+     * @return {Number} Left value (in pixels)
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#left|left position}
+     * @method setLeft
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value Left value (in pixels)
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#scaleX|scaleX} value
+     * @method getScaleX
+     * @memberOf fabric.Object.prototype
+     * @return {Number} scaleX value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#scaleX|scaleX} value
+     * @method setScaleX
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value scaleX value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#scaleY|scaleY} value
+     * @method getScaleY
+     * @memberOf fabric.Object.prototype
+     * @return {Number} scaleY value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#scaleY|scaleY} value
+     * @method setScaleY
+     * @memberOf fabric.Object.prototype
+     * @param {Number} value scaleY value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#flipX|flipX} value
+     * @method getFlipX
+     * @memberOf fabric.Object.prototype
+     * @return {Boolean} flipX value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#flipX|flipX} value
+     * @method setFlipX
+     * @memberOf fabric.Object.prototype
+     * @param {Boolean} value flipX value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's {@link fabric.Object#flipY|flipY} value
+     * @method getFlipY
+     * @memberOf fabric.Object.prototype
+     * @return {Boolean} flipY value
+     */
+
+    /**
+     * Sets object's {@link fabric.Object#flipY|flipY} value
+     * @method setFlipY
+     * @memberOf fabric.Object.prototype
+     * @param {Boolean} value flipY value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+
+    /**
+     * Type of an object (rect, circle, path, etc.).
+     * Note that this property is meant to be read-only and not meant to be modified.
+     * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly.
+     * @type String
+     * @default
+     */
+    type:                     'object',
+
+    /**
+     * Horizontal origin of transformation of an object (one of "left", "right", "center")
+     * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups
+     * @type String
+     * @default
+     */
+    originX:                  'left',
+
+    /**
+     * Vertical origin of transformation of an object (one of "top", "bottom", "center")
+     * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups
+     * @type String
+     * @default
+     */
+    originY:                  'top',
+
+    /**
+     * Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}
+     * @type Number
+     * @default
+     */
+    top:                      0,
+
+    /**
+     * Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}
+     * @type Number
+     * @default
+     */
+    left:                     0,
+
+    /**
+     * Object width
+     * @type Number
+     * @default
+     */
+    width:                    0,
+
+    /**
+     * Object height
+     * @type Number
+     * @default
+     */
+    height:                   0,
+
+    /**
+     * Object scale factor (horizontal)
+     * @type Number
+     * @default
+     */
+    scaleX:                   1,
+
+    /**
+     * Object scale factor (vertical)
+     * @type Number
+     * @default
+     */
+    scaleY:                   1,
+
+    /**
+     * When true, an object is rendered as flipped horizontally
+     * @type Boolean
+     * @default
+     */
+    flipX:                    false,
+
+    /**
+     * When true, an object is rendered as flipped vertically
+     * @type Boolean
+     * @default
+     */
+    flipY:                    false,
+
+    /**
+     * Opacity of an object
+     * @type Number
+     * @default
+     */
+    opacity:                  1,
+
+    /**
+     * Angle of rotation of an object (in degrees)
+     * @type Number
+     * @default
+     */
+    angle:                    0,
+
+    /**
+     * Angle of skew on x axes of an object (in degrees)
+     * @type Number
+     * @default
+     */
+    skewX:                    0,
+
+    /**
+     * Angle of skew on y axes of an object (in degrees)
+     * @type Number
+     * @default
+     */
+    skewY:                    0,
+
+    /**
+     * Size of object's controlling corners (in pixels)
+     * @type Number
+     * @default
+     */
+    cornerSize:               13,
+
+    /**
+     * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)
+     * @type Boolean
+     * @default
+     */
+    transparentCorners:       true,
+
+    /**
+     * Default cursor value used when hovering over this object on canvas
+     * @type String
+     * @default
+     */
+    hoverCursor:              null,
+
+    /**
+     * Default cursor value used when moving this object on canvas
+     * @type String
+     * @default
+     */
+    moveCursor:               null,
+
+    /**
+     * Padding between object and its controlling borders (in pixels)
+     * @type Number
+     * @default
+     */
+    padding:                  0,
+
+    /**
+     * Color of controlling borders of an object (when it's active)
+     * @type String
+     * @default
+     */
+    borderColor:              'rgba(102,153,255,0.75)',
+
+    /**
+     * Array specifying dash pattern of an object's borders (hasBorder must be true)
+     * @since 1.6.2
+     * @type Array
+     */
+    borderDashArray:          null,
+
+    /**
+     * Color of controlling corners of an object (when it's active)
+     * @type String
+     * @default
+     */
+    cornerColor:              'rgba(102,153,255,0.5)',
+
+    /**
+     * Color of controlling corners of an object (when it's active and transparentCorners false)
+     * @since 1.6.2
+     * @type String
+     * @default
+     */
+    cornerStrokeColor:        null,
+
+    /**
+     * Specify style of control, 'rect' or 'circle'
+     * @since 1.6.2
+     * @type String
+     */
+    cornerStyle:          'rect',
+
+    /**
+     * Array specifying dash pattern of an object's control (hasBorder must be true)
+     * @since 1.6.2
+     * @type Array
+     */
+    cornerDashArray:          null,
+
+    /**
+     * When true, this object will use center point as the origin of transformation
+     * when being scaled via the controls.
+     * <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
+     * @since 1.3.4
+     * @type Boolean
+     * @default
+     */
+    centeredScaling:          false,
+
+    /**
+     * When true, this object will use center point as the origin of transformation
+     * when being rotated via the controls.
+     * <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
+     * @since 1.3.4
+     * @type Boolean
+     * @default
+     */
+    centeredRotation:         true,
+
+    /**
+     * Color of object's fill
+     * @type String
+     * @default
+     */
+    fill:                     'rgb(0,0,0)',
+
+    /**
+     * Fill rule used to fill an object
+     * accepted values are nonzero, evenodd
+     * <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead)
+     * @type String
+     * @default
+     */
+    fillRule:                 'nonzero',
+
+    /**
+     * Composite rule used for canvas globalCompositeOperation
+     * @type String
+     * @default
+     */
+    globalCompositeOperation: 'source-over',
+
+    /**
+     * Background color of an object. Only works with text objects at the moment.
+     * @type String
+     * @default
+     */
+    backgroundColor:          '',
+
+    /**
+     * Selection Background color of an object. colored layer behind the object when it is active.
+     * does not mix good with globalCompositeOperation methods.
+     * @type String
+     * @default
+     */
+    selectionBackgroundColor:          '',
+
+    /**
+     * When defined, an object is rendered via stroke and this property specifies its color
+     * @type String
+     * @default
+     */
+    stroke:                   null,
+
+    /**
+     * Width of a stroke used to render this object
+     * @type Number
+     * @default
+     */
+    strokeWidth:              1,
+
+    /**
+     * Array specifying dash pattern of an object's stroke (stroke must be defined)
+     * @type Array
+     */
+    strokeDashArray:          null,
+
+    /**
+     * Line endings style of an object's stroke (one of "butt", "round", "square")
+     * @type String
+     * @default
+     */
+    strokeLineCap:            'butt',
+
+    /**
+     * Corner style of an object's stroke (one of "bevil", "round", "miter")
+     * @type String
+     * @default
+     */
+    strokeLineJoin:           'miter',
+
+    /**
+     * Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke
+     * @type Number
+     * @default
+     */
+    strokeMiterLimit:         10,
+
+    /**
+     * Shadow object representing shadow of this shape
+     * @type fabric.Shadow
+     * @default
+     */
+    shadow:                   null,
+
+    /**
+     * Opacity of object's controlling borders when object is active and moving
+     * @type Number
+     * @default
+     */
+    borderOpacityWhenMoving:  0.4,
+
+    /**
+     * Scale factor of object's controlling borders
+     * @type Number
+     * @default
+     */
+    borderScaleFactor:        1,
+
+    /**
+     * Transform matrix (similar to SVG's transform matrix)
+     * @type Array
+     */
+    transformMatrix:          null,
+
+    /**
+     * Minimum allowed scale value of an object
+     * @type Number
+     * @default
+     */
+    minScaleLimit:            0.01,
+
+    /**
+     * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).
+     * But events still fire on it.
+     * @type Boolean
+     * @default
+     */
+    selectable:               true,
+
+    /**
+     * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4
+     * @type Boolean
+     * @default
+     */
+    evented:                  true,
+
+    /**
+     * When set to `false`, an object is not rendered on canvas
+     * @type Boolean
+     * @default
+     */
+    visible:                  true,
+
+    /**
+     * When set to `false`, object's controls are not displayed and can not be used to manipulate object
+     * @type Boolean
+     * @default
+     */
+    hasControls:              true,
+
+    /**
+     * When set to `false`, object's controlling borders are not rendered
+     * @type Boolean
+     * @default
+     */
+    hasBorders:               true,
+
+    /**
+     * When set to `false`, object's controlling rotating point will not be visible or selectable
+     * @type Boolean
+     * @default
+     */
+    hasRotatingPoint:         true,
+
+    /**
+     * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`)
+     * @type Number
+     * @default
+     */
+    rotatingPointOffset:      40,
+
+    /**
+     * When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
+     * @type Boolean
+     * @default
+     */
+    perPixelTargetFind:       false,
+
+    /**
+     * When `false`, default object's values are not included in its serialization
+     * @type Boolean
+     * @default
+     */
+    includeDefaultValues:     true,
+
+    /**
+     * Function that determines clipping of an object (context is passed as a first argument)
+     * Note that context origin is at the object's center point (not left/top corner)
+     * @type Function
+     */
+    clipTo:                   null,
+
+    /**
+     * When `true`, object horizontal movement is locked
+     * @type Boolean
+     * @default
+     */
+    lockMovementX:            false,
+
+    /**
+     * When `true`, object vertical movement is locked
+     * @type Boolean
+     * @default
+     */
+    lockMovementY:            false,
+
+    /**
+     * When `true`, object rotation is locked
+     * @type Boolean
+     * @default
+     */
+    lockRotation:             false,
+
+    /**
+     * When `true`, object horizontal scaling is locked
+     * @type Boolean
+     * @default
+     */
+    lockScalingX:             false,
+
+    /**
+     * When `true`, object vertical scaling is locked
+     * @type Boolean
+     * @default
+     */
+    lockScalingY:             false,
+
+    /**
+     * When `true`, object non-uniform scaling is locked
+     * @type Boolean
+     * @default
+     */
+    lockUniScaling:           false,
+
+    /**
+     * When `true`, object horizontal skewing is locked
+     * @type Boolean
+     * @default
+     */
+    lockSkewingX:             false,
+
+    /**
+     * When `true`, object vertical skewing is locked
+     * @type Boolean
+     * @default
+     */
+    lockSkewingY:             false,
+
+    /**
+     * When `true`, object cannot be flipped by scaling into negative values
+     * @type Boolean
+     * @default
+     */
+
+    lockScalingFlip:          false,
+
+    /**
+     * When `true`, object is not exported in SVG or OBJECT/JSON
+     * since 1.6.3
+     * @type Boolean
+     * @default
+     */
+
+    excludeFromExport:          false,
+
+    /**
+     * List of properties to consider when checking if state
+     * of an object is changed (fabric.Object#hasStateChanged)
+     * as well as for history (undo/redo) purposes
+     * @type Array
+     */
+    stateProperties:  (
+      'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +
+      'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' +
+      'angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor ' +
+      'skewX skewY'
+    ).split(' '),
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object
+     */
+    initialize: function(options) {
+      if (options) {
+        this.setOptions(options);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options object
+     */
+    _initGradient: function(options) {
+      if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {
+        this.set('fill', new fabric.Gradient(options.fill));
+      }
+      if (options.stroke && options.stroke.colorStops && !(options.stroke instanceof fabric.Gradient)) {
+        this.set('stroke', new fabric.Gradient(options.stroke));
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options object
+     */
+    _initPattern: function(options) {
+      if (options.fill && options.fill.source && !(options.fill instanceof fabric.Pattern)) {
+        this.set('fill', new fabric.Pattern(options.fill));
+      }
+      if (options.stroke && options.stroke.source && !(options.stroke instanceof fabric.Pattern)) {
+        this.set('stroke', new fabric.Pattern(options.stroke));
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options object
+     */
+    _initClipping: function(options) {
+      if (!options.clipTo || typeof options.clipTo !== 'string') {
+        return;
+      }
+
+      var functionBody = fabric.util.getFunctionBody(options.clipTo);
+      if (typeof functionBody !== 'undefined') {
+        this.clipTo = new Function('ctx', functionBody);
+      }
+    },
+
+    /**
+     * Sets object's properties from options
+     * @param {Object} [options] Options object
+     */
+    setOptions: function(options) {
+      for (var prop in options) {
+        this.set(prop, options[prop]);
+      }
+      this._initGradient(options);
+      this._initPattern(options);
+      this._initClipping(options);
+    },
+
+    /**
+     * Transforms context when rendering an object
+     * @param {CanvasRenderingContext2D} ctx Context
+     * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node
+     */
+    transform: function(ctx, fromLeft) {
+      if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {
+        this.group.transform(ctx);
+      }
+      var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
+      ctx.translate(center.x, center.y);
+      ctx.rotate(degreesToRadians(this.angle));
+      ctx.scale(
+        this.scaleX * (this.flipX ? -1 : 1),
+        this.scaleY * (this.flipY ? -1 : 1)
+      );
+      ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
+      ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
+    },
+
+    /**
+     * Returns an object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
+
+          object = {
+            type:                     this.type,
+            originX:                  this.originX,
+            originY:                  this.originY,
+            left:                     toFixed(this.left, NUM_FRACTION_DIGITS),
+            top:                      toFixed(this.top, NUM_FRACTION_DIGITS),
+            width:                    toFixed(this.width, NUM_FRACTION_DIGITS),
+            height:                   toFixed(this.height, NUM_FRACTION_DIGITS),
+            fill:                     (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,
+            stroke:                   (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,
+            strokeWidth:              toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),
+            strokeDashArray:          this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray,
+            strokeLineCap:            this.strokeLineCap,
+            strokeLineJoin:           this.strokeLineJoin,
+            strokeMiterLimit:         toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),
+            scaleX:                   toFixed(this.scaleX, NUM_FRACTION_DIGITS),
+            scaleY:                   toFixed(this.scaleY, NUM_FRACTION_DIGITS),
+            angle:                    toFixed(this.getAngle(), NUM_FRACTION_DIGITS),
+            flipX:                    this.flipX,
+            flipY:                    this.flipY,
+            opacity:                  toFixed(this.opacity, NUM_FRACTION_DIGITS),
+            shadow:                   (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,
+            visible:                  this.visible,
+            clipTo:                   this.clipTo && String(this.clipTo),
+            backgroundColor:          this.backgroundColor,
+            fillRule:                 this.fillRule,
+            globalCompositeOperation: this.globalCompositeOperation,
+            transformMatrix:          this.transformMatrix ? this.transformMatrix.concat() : this.transformMatrix,
+            skewX:                    toFixed(this.skewX, NUM_FRACTION_DIGITS),
+            skewY:                    toFixed(this.skewY, NUM_FRACTION_DIGITS)
+          };
+
+      fabric.util.populateWithProperties(this, object, propertiesToInclude);
+
+      if (!this.includeDefaultValues) {
+        object = this._removeDefaultValues(object);
+      }
+
+      return object;
+    },
+
+    /**
+     * Returns (dataless) object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toDatalessObject: function(propertiesToInclude) {
+      // will be overwritten by subclasses
+      return this.toObject(propertiesToInclude);
+    },
+
+    /**
+     * @private
+     * @param {Object} object
+     */
+    _removeDefaultValues: function(object) {
+      var prototype = fabric.util.getKlass(object.type).prototype,
+          stateProperties = prototype.stateProperties;
+      stateProperties.forEach(function(prop) {
+        if (object[prop] === prototype[prop]) {
+          delete object[prop];
+        }
+        var isArray = Object.prototype.toString.call(object[prop]) === '[object Array]' &&
+                      Object.prototype.toString.call(prototype[prop]) === '[object Array]';
+
+        // basically a check for [] === []
+        if (isArray && object[prop].length === 0 && prototype[prop].length === 0) {
+          delete object[prop];
+        }
+      });
+
+      return object;
+    },
+
+    /**
+     * Returns a string representation of an instance
+     * @return {String}
+     */
+    toString: function() {
+      return '#<fabric.' + capitalize(this.type) + '>';
+    },
+
+    /**
+     * Basic getter
+     * @param {String} property Property name
+     * @return {*} value of a property
+     */
+    get: function(property) {
+      return this[property];
+    },
+
+    /**
+     * Return the object scale factor counting also the group scaling
+     * @return {Object} object with scaleX and scaleY properties
+     */
+    getObjectScaling: function() {
+      var scaleX = this.scaleX, scaleY = this.scaleY;
+      if (this.group) {
+        var scaling = this.group.getObjectScaling();
+        scaleX *= scaling.scaleX;
+        scaleY *= scaling.scaleY;
+      }
+      return { scaleX: scaleX, scaleY: scaleY };
+    },
+
+    /**
+     * @private
+     */
+    _setObject: function(obj) {
+      for (var prop in obj) {
+        this._set(prop, obj[prop]);
+      }
+    },
+
+    /**
+     * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.
+     * @param {String|Object} key Property name or object (if object, iterate over the object properties)
+     * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    set: function(key, value) {
+      if (typeof key === 'object') {
+        this._setObject(key);
+      }
+      else {
+        if (typeof value === 'function' && key !== 'clipTo') {
+          this._set(key, value(this.get(key)));
+        }
+        else {
+          this._set(key, value);
+        }
+      }
+      return this;
+    },
+
+    /**
+     * @private
+     * @param {String} key
+     * @param {*} value
+     * @return {fabric.Object} thisArg
+     */
+    _set: function(key, value) {
+      var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');
+
+      if (shouldConstrainValue) {
+        value = this._constrainScale(value);
+      }
+      if (key === 'scaleX' && value < 0) {
+        this.flipX = !this.flipX;
+        value *= -1;
+      }
+      else if (key === 'scaleY' && value < 0) {
+        this.flipY = !this.flipY;
+        value *= -1;
+      }
+      else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) {
+        value = new fabric.Shadow(value);
+      }
+
+      this[key] = value;
+
+      if (key === 'width' || key === 'height') {
+        this.minScaleLimit = Math.min(0.1, 1 / Math.max(this.width, this.height));
+      }
+
+      return this;
+    },
+
+    /**
+     * This callback function is called by the parent group of an object every
+     * time a non-delegated property changes on the group. It is passed the key
+     * and value as parameters. Not adding in this function's signature to avoid
+     * Travis build error about unused variables.
+     */
+    setOnGroup: function() {
+      // implemented by sub-classes, as needed.
+    },
+
+    /**
+     * Toggles specified property from `true` to `false` or from `false` to `true`
+     * @param {String} property Property to toggle
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    toggle: function(property) {
+      var value = this.get(property);
+      if (typeof value === 'boolean') {
+        this.set(property, !value);
+      }
+      return this;
+    },
+
+    /**
+     * Sets sourcePath of an object
+     * @param {String} value Value to set sourcePath to
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setSourcePath: function(value) {
+      this.sourcePath = value;
+      return this;
+    },
+
+    /**
+     * Retrieves viewportTransform from Object's canvas if possible
+     * @method getViewportTransform
+     * @memberOf fabric.Object.prototype
+     * @return {Boolean} flipY value // TODO
+     */
+    getViewportTransform: function() {
+      if (this.canvas && this.canvas.viewportTransform) {
+        return this.canvas.viewportTransform;
+      }
+      return [1, 0, 0, 1, 0, 0];
+    },
+
+    /**
+     * Renders an object on a specified context
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} [noTransform] When true, context is not transformed
+     */
+    render: function(ctx, noTransform) {
+      // do not render if width/height are zeros or object is not visible
+      if ((this.width === 0 && this.height === 0) || !this.visible) {
+        return;
+      }
+
+      ctx.save();
+
+      //setup fill rule for current object
+      this._setupCompositeOperation(ctx);
+      this.drawSelectionBackground(ctx);
+      if (!noTransform) {
+        this.transform(ctx);
+      }
+      this._setOpacity(ctx);
+      this._setShadow(ctx);
+      this._renderBackground(ctx);
+      this._setStrokeStyles(ctx);
+      this._setFillStyles(ctx);
+      if (this.transformMatrix) {
+        ctx.transform.apply(ctx, this.transformMatrix);
+      }
+      this.clipTo && fabric.util.clipContext(this, ctx);
+      this._render(ctx, noTransform);
+      this.clipTo && ctx.restore();
+
+      ctx.restore();
+    },
+
+    /**
+     * Draws a background for the object big as its width and height;
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderBackground: function(ctx) {
+      if (!this.backgroundColor) {
+        return;
+      }
+
+      ctx.fillStyle = this.backgroundColor;
+
+      ctx.fillRect(
+        -this.width / 2,
+        -this.height / 2,
+        this.width,
+        this.height
+      );
+      // if there is background color no other shadows
+      // should be casted
+      this._removeShadow(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _setOpacity: function(ctx) {
+      if (this.group) {
+        this.group._setOpacity(ctx);
+      }
+      ctx.globalAlpha *= this.opacity;
+    },
+
+    _setStrokeStyles: function(ctx) {
+      if (this.stroke) {
+        ctx.lineWidth = this.strokeWidth;
+        ctx.lineCap = this.strokeLineCap;
+        ctx.lineJoin = this.strokeLineJoin;
+        ctx.miterLimit = this.strokeMiterLimit;
+        ctx.strokeStyle = this.stroke.toLive
+          ? this.stroke.toLive(ctx, this)
+          : this.stroke;
+      }
+    },
+
+    _setFillStyles: function(ctx) {
+      if (this.fill) {
+        ctx.fillStyle = this.fill.toLive
+          ? this.fill.toLive(ctx, this)
+          : this.fill;
+      }
+    },
+
+    /**
+     * @private
+     * Sets line dash
+     * @param {CanvasRenderingContext2D} ctx Context to set the dash line on
+     * @param {Array} dashArray array representing dashes
+     * @param {Function} alternative function to call if browaser does not support lineDash
+     */
+    _setLineDash: function(ctx, dashArray, alternative) {
+      if (!dashArray) {
+        return;
+      }
+      // Spec requires the concatenation of two copies the dash list when the number of elements is odd
+      if (1 & dashArray.length) {
+        dashArray.push.apply(dashArray, dashArray);
+      }
+      if (supportsLineDash) {
+        ctx.setLineDash(dashArray);
+      }
+      else {
+        alternative && alternative(ctx);
+      }
+    },
+
+    /**
+     * Renders controls and borders for the object
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} [noTransform] When true, context is not transformed
+     */
+    _renderControls: function(ctx, noTransform) {
+      if (!this.active || noTransform
+          || (this.group && this.group !== this.canvas.getActiveGroup())) {
+        return;
+      }
+
+      var vpt = this.getViewportTransform(),
+          matrix = this.calcTransformMatrix(),
+          options;
+      matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);
+      options = fabric.util.qrDecompose(matrix);
+
+      ctx.save();
+      ctx.translate(options.translateX, options.translateY);
+      ctx.lineWidth = 1 * this.borderScaleFactor;
+      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
+
+      if (this.group && this.group === this.canvas.getActiveGroup()) {
+        ctx.rotate(degreesToRadians(options.angle));
+        this.drawBordersInGroup(ctx, options);
+      }
+      else {
+        ctx.rotate(degreesToRadians(this.angle));
+        this.drawBorders(ctx);
+      }
+      this.drawControls(ctx);
+      ctx.restore();
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _setShadow: function(ctx) {
+      if (!this.shadow) {
+        return;
+      }
+
+      var multX = (this.canvas && this.canvas.viewportTransform[0]) || 1,
+          multY = (this.canvas && this.canvas.viewportTransform[3]) || 1,
+          scaling = this.getObjectScaling();
+      if (this.canvas && this.canvas._isRetinaScaling()) {
+        multX *= fabric.devicePixelRatio;
+        multY *= fabric.devicePixelRatio;
+      }
+      ctx.shadowColor = this.shadow.color;
+      ctx.shadowBlur = this.shadow.blur * (multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;
+      ctx.shadowOffsetX = this.shadow.offsetX * multX * scaling.scaleX;
+      ctx.shadowOffsetY = this.shadow.offsetY * multY * scaling.scaleY;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _removeShadow: function(ctx) {
+      if (!this.shadow) {
+        return;
+      }
+
+      ctx.shadowColor = '';
+      ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderFill: function(ctx) {
+      if (!this.fill) {
+        return;
+      }
+
+      ctx.save();
+      if (this.fill.gradientTransform) {
+        var g = this.fill.gradientTransform;
+        ctx.transform.apply(ctx, g);
+      }
+      if (this.fill.toLive) {
+        ctx.translate(
+          -this.width / 2 + this.fill.offsetX || 0,
+          -this.height / 2 + this.fill.offsetY || 0);
+      }
+      if (this.fillRule === 'evenodd') {
+        ctx.fill('evenodd');
+      }
+      else {
+        ctx.fill();
+      }
+      ctx.restore();
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderStroke: function(ctx) {
+      if (!this.stroke || this.strokeWidth === 0) {
+        return;
+      }
+
+      if (this.shadow && !this.shadow.affectStroke) {
+        this._removeShadow(ctx);
+      }
+
+      ctx.save();
+
+      this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
+      if (this.stroke.gradientTransform) {
+        var g = this.stroke.gradientTransform;
+        ctx.transform.apply(ctx, g);
+      }
+      if (this.stroke.toLive) {
+        ctx.translate(
+          -this.width / 2 + this.stroke.offsetX || 0,
+          -this.height / 2 + this.stroke.offsetY || 0);
+      }
+      ctx.stroke();
+      ctx.restore();
+    },
+
+    /**
+     * Clones an instance, some objects are async, so using callback method will work for every object.
+     * Using the direct return does not work for images and groups.
+     * @param {Function} callback Callback is invoked with a clone as a first argument
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {fabric.Object} clone of an instance
+     */
+    clone: function(callback, propertiesToInclude) {
+      if (this.constructor.fromObject) {
+        return this.constructor.fromObject(this.toObject(propertiesToInclude), callback);
+      }
+      return new fabric.Object(this.toObject(propertiesToInclude));
+    },
+
+    /**
+     * Creates an instance of fabric.Image out of an object
+     * @param {Function} callback callback, invoked with an instance as a first argument
+     * @param {Object} [options] for clone as image, passed to toDataURL
+     * @param {Boolean} [options.enableRetinaScaling] enable retina scaling for the cloned image
+     * @return {fabric.Object} thisArg
+     */
+    cloneAsImage: function(callback, options) {
+      var dataUrl = this.toDataURL(options);
+      fabric.util.loadImage(dataUrl, function(img) {
+        if (callback) {
+          callback(new fabric.Image(img));
+        }
+      });
+      return this;
+    },
+
+    /**
+     * Converts an object into a data-url-like string
+     * @param {Object} options Options object
+     * @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
+     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
+     * @param {Number} [options.multiplier=1] Multiplier to scale by
+     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
+     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
+     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14
+     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14
+     * @param {Boolean} [options.enableRetina] Enable retina scaling for clone image. Introduce in 1.6.4
+     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
+     */
+    toDataURL: function(options) {
+      options || (options = { });
+
+      var el = fabric.util.createCanvasElement(),
+          boundingRect = this.getBoundingRect();
+
+      el.width = boundingRect.width;
+      el.height = boundingRect.height;
+      fabric.util.wrapElement(el, 'div');
+      var canvas = new fabric.StaticCanvas(el, { enableRetinaScaling: options.enableRetinaScaling });
+      // to avoid common confusion https://github.com/kangax/fabric.js/issues/806
+      if (options.format === 'jpg') {
+        options.format = 'jpeg';
+      }
+
+      if (options.format === 'jpeg') {
+        canvas.backgroundColor = '#fff';
+      }
+
+      var origParams = {
+        active: this.get('active'),
+        left: this.getLeft(),
+        top: this.getTop()
+      };
+
+      this.set('active', false);
+      this.setPositionByOrigin(new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2), 'center', 'center');
+
+      var originalCanvas = this.canvas;
+      canvas.add(this);
+      var data = canvas.toDataURL(options);
+
+      this.set(origParams).setCoords();
+      this.canvas = originalCanvas;
+
+      canvas.dispose();
+      canvas = null;
+
+      return data;
+    },
+
+    /**
+     * Returns true if specified type is identical to the type of an instance
+     * @param {String} type Type to check against
+     * @return {Boolean}
+     */
+    isType: function(type) {
+      return this.type === type;
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return 0;
+    },
+
+    /**
+     * Returns a JSON representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} JSON
+     */
+    toJSON: function(propertiesToInclude) {
+      // delegate, not alias
+      return this.toObject(propertiesToInclude);
+    },
+
+    /**
+     * Sets gradient (fill or stroke) of an object
+     * <b>Backwards incompatibility note:</b> This method was named "setGradientFill" until v1.1.0
+     * @param {String} property Property name 'stroke' or 'fill'
+     * @param {Object} [options] Options object
+     * @param {String} [options.type] Type of gradient 'radial' or 'linear'
+     * @param {Number} [options.x1=0] x-coordinate of start point
+     * @param {Number} [options.y1=0] y-coordinate of start point
+     * @param {Number} [options.x2=0] x-coordinate of end point
+     * @param {Number} [options.y2=0] y-coordinate of end point
+     * @param {Number} [options.r1=0] Radius of start point (only for radial gradients)
+     * @param {Number} [options.r2=0] Radius of end point (only for radial gradients)
+     * @param {Object} [options.colorStops] Color stops object eg. {0: 'ff0000', 1: '000000'}
+     * @param {Object} [options.gradientTransform] transforMatrix for gradient
+     * @return {fabric.Object} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo}
+     * @example <caption>Set linear gradient</caption>
+     * object.setGradient('fill', {
+     *   type: 'linear',
+     *   x1: -object.width / 2,
+     *   y1: 0,
+     *   x2: object.width / 2,
+     *   y2: 0,
+     *   colorStops: {
+     *     0: 'red',
+     *     0.5: '#005555',
+     *     1: 'rgba(0,0,255,0.5)'
+     *   }
+     * });
+     * canvas.renderAll();
+     * @example <caption>Set radial gradient</caption>
+     * object.setGradient('fill', {
+     *   type: 'radial',
+     *   x1: 0,
+     *   y1: 0,
+     *   x2: 0,
+     *   y2: 0,
+     *   r1: object.width / 2,
+     *   r2: 10,
+     *   colorStops: {
+     *     0: 'red',
+     *     0.5: '#005555',
+     *     1: 'rgba(0,0,255,0.5)'
+     *   }
+     * });
+     * canvas.renderAll();
+     */
+    setGradient: function(property, options) {
+      options || (options = { });
+
+      var gradient = { colorStops: [] };
+
+      gradient.type = options.type || (options.r1 || options.r2 ? 'radial' : 'linear');
+      gradient.coords = {
+        x1: options.x1,
+        y1: options.y1,
+        x2: options.x2,
+        y2: options.y2
+      };
+
+      if (options.r1 || options.r2) {
+        gradient.coords.r1 = options.r1;
+        gradient.coords.r2 = options.r2;
+      }
+
+      options.gradientTransform && (gradient.gradientTransform = options.gradientTransform);
+
+      for (var position in options.colorStops) {
+        var color = new fabric.Color(options.colorStops[position]);
+        gradient.colorStops.push({
+          offset: position,
+          color: color.toRgb(),
+          opacity: color.getAlpha()
+        });
+      }
+
+      return this.set(property, fabric.Gradient.forObject(this, gradient));
+    },
+
+    /**
+     * Sets pattern fill of an object
+     * @param {Object} options Options object
+     * @param {(String|HTMLImageElement)} options.source Pattern source
+     * @param {String} [options.repeat=repeat] Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)
+     * @param {Number} [options.offsetX=0] Pattern horizontal offset from object's left/top corner
+     * @param {Number} [options.offsetY=0] Pattern vertical offset from object's left/top corner
+     * @return {fabric.Object} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo}
+     * @example <caption>Set pattern</caption>
+     * fabric.util.loadImage('http://fabricjs.com/assets/escheresque_ste.png', function(img) {
+     *   object.setPatternFill({
+     *     source: img,
+     *     repeat: 'repeat'
+     *   });
+     *   canvas.renderAll();
+     * });
+     */
+    setPatternFill: function(options) {
+      return this.set('fill', new fabric.Pattern(options));
+    },
+
+    /**
+     * Sets {@link fabric.Object#shadow|shadow} of an object
+     * @param {Object|String} [options] Options object or string (e.g. "2px 2px 10px rgba(0,0,0,0.2)")
+     * @param {String} [options.color=rgb(0,0,0)] Shadow color
+     * @param {Number} [options.blur=0] Shadow blur
+     * @param {Number} [options.offsetX=0] Shadow horizontal offset
+     * @param {Number} [options.offsetY=0] Shadow vertical offset
+     * @return {fabric.Object} thisArg
+     * @chainable
+     * @see {@link http://jsfiddle.net/fabricjs/7gvJG/|jsFiddle demo}
+     * @example <caption>Set shadow with string notation</caption>
+     * object.setShadow('2px 2px 10px rgba(0,0,0,0.2)');
+     * canvas.renderAll();
+     * @example <caption>Set shadow with object notation</caption>
+     * object.setShadow({
+     *   color: 'red',
+     *   blur: 10,
+     *   offsetX: 20,
+     *   offsetY: 20
+     * });
+     * canvas.renderAll();
+     */
+    setShadow: function(options) {
+      return this.set('shadow', options ? new fabric.Shadow(options) : null);
+    },
+
+    /**
+     * Sets "color" of an instance (alias of `set('fill', &hellip;)`)
+     * @param {String} color Color value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setColor: function(color) {
+      this.set('fill', color);
+      return this;
+    },
+
+    /**
+     * Sets "angle" of an instance
+     * @param {Number} angle Angle value (in degrees)
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setAngle: function(angle) {
+      var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;
+
+      if (shouldCenterOrigin) {
+        this._setOriginToCenter();
+      }
+
+      this.set('angle', angle);
+
+      if (shouldCenterOrigin) {
+        this._resetOrigin();
+      }
+
+      return this;
+    },
+
+    /**
+     * Centers object horizontally on canvas to which it was added last.
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    centerH: function () {
+      this.canvas && this.canvas.centerObjectH(this);
+      return this;
+    },
+
+    /**
+     * Centers object horizontally on current viewport of canvas to which it was added last.
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    viewportCenterH: function () {
+      this.canvas && this.canvas.viewportCenterObjectH(this);
+      return this;
+    },
+
+    /**
+     * Centers object vertically on canvas to which it was added last.
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    centerV: function () {
+      this.canvas && this.canvas.centerObjectV(this);
+      return this;
+    },
+
+    /**
+     * Centers object vertically on current viewport of canvas to which it was added last.
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    viewportCenterV: function () {
+      this.canvas && this.canvas.viewportCenterObjectV(this);
+      return this;
+    },
+
+    /**
+     * Centers object vertically and horizontally on canvas to which is was added last
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    center: function () {
+      this.canvas && this.canvas.centerObject(this);
+      return this;
+    },
+
+    /**
+     * Centers object on current viewport of canvas to which it was added last.
+     * You might need to call `setCoords` on an object after centering, to update controls area.
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    viewportCenter: function () {
+      this.canvas && this.canvas.viewportCenterObject(this);
+      return this;
+    },
+
+    /**
+     * Removes object from canvas to which it was added last
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    remove: function() {
+      this.canvas && this.canvas.remove(this);
+      return this;
+    },
+
+    /**
+     * Returns coordinates of a pointer relative to an object
+     * @param {Event} e Event to operate upon
+     * @param {Object} [pointer] Pointer to operate upon (instead of event)
+     * @return {Object} Coordinates of a pointer (x, y)
+     */
+    getLocalPointer: function(e, pointer) {
+      pointer = pointer || this.canvas.getPointer(e);
+      var pClicked = new fabric.Point(pointer.x, pointer.y),
+          objectLeftTop = this._getLeftTopCoords();
+      if (this.angle) {
+        pClicked = fabric.util.rotatePoint(
+          pClicked, objectLeftTop, fabric.util.degreesToRadians(-this.angle));
+      }
+      return {
+        x: pClicked.x - objectLeftTop.x,
+        y: pClicked.y - objectLeftTop.y
+      };
+    },
+
+    /**
+     * Sets canvas globalCompositeOperation for specific object
+     * custom composition operation for the particular object can be specifed using globalCompositeOperation property
+     * @param {CanvasRenderingContext2D} ctx Rendering canvas context
+     */
+    _setupCompositeOperation: function (ctx) {
+      if (this.globalCompositeOperation) {
+        ctx.globalCompositeOperation = this.globalCompositeOperation;
+      }
+    }
+  });
+
+  fabric.util.createAccessors(fabric.Object);
+
+  /**
+   * Alias for {@link fabric.Object.prototype.setAngle}
+   * @alias rotate -> setAngle
+   * @memberOf fabric.Object
+   */
+  fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle;
+
+  extend(fabric.Object.prototype, fabric.Observable);
+
+  /**
+   * Defines the number of fraction digits to use when serializing object values.
+   * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.
+   * @static
+   * @memberOf fabric.Object
+   * @constant
+   * @type Number
+   */
+  fabric.Object.NUM_FRACTION_DIGITS = 2;
+
+  /**
+   * Unique id used internally when creating SVG elements
+   * @static
+   * @memberOf fabric.Object
+   * @type Number
+   */
+  fabric.Object.__uid = 0;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function() {
+
+  var degreesToRadians = fabric.util.degreesToRadians,
+      originXOffset = {
+        left: -0.5,
+        center: 0,
+        right: 0.5
+      },
+      originYOffset = {
+        top: -0.5,
+        center: 0,
+        bottom: 0.5
+      };
+
+  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+    /**
+     * Translates the coordinates from origin to center coordinates (based on the object's dimensions)
+     * @param {fabric.Point} point The point which corresponds to the originX and originY params
+     * @param {String} fromOriginX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} fromOriginY Vertical origin: 'top', 'center' or 'bottom'
+     * @param {String} toOriginX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} toOriginY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {fabric.Point}
+     */
+    translateToGivenOrigin: function(point, fromOriginX, fromOriginY, toOriginX, toOriginY) {
+      var x = point.x,
+          y = point.y,
+          offsetX, offsetY, dim;
+
+      if (typeof fromOriginX === 'string') {
+        fromOriginX = originXOffset[fromOriginX];
+      }
+      else {
+        fromOriginX -= 0.5;
+      }
+
+      if (typeof toOriginX === 'string') {
+        toOriginX = originXOffset[toOriginX];
+      }
+      else {
+        toOriginX -= 0.5;
+      }
+
+      offsetX = toOriginX - fromOriginX;
+
+      if (typeof fromOriginY === 'string') {
+        fromOriginY = originYOffset[fromOriginY];
+      }
+      else {
+        fromOriginY -= 0.5;
+      }
+
+      if (typeof toOriginY === 'string') {
+        toOriginY = originYOffset[toOriginY];
+      }
+      else {
+        toOriginY -= 0.5;
+      }
+
+      offsetY = toOriginY - fromOriginY;
+
+      if (offsetX || offsetY) {
+        dim = this._getTransformedDimensions();
+        x = point.x + offsetX * dim.x;
+        y = point.y + offsetY * dim.y;
+      }
+
+      return new fabric.Point(x, y);
+    },
+
+    /**
+     * Translates the coordinates from origin to center coordinates (based on the object's dimensions)
+     * @param {fabric.Point} point The point which corresponds to the originX and originY params
+     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {fabric.Point}
+     */
+    translateToCenterPoint: function(point, originX, originY) {
+      var p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center');
+      if (this.angle) {
+        return fabric.util.rotatePoint(p, point, degreesToRadians(this.angle));
+      }
+      return p;
+    },
+
+    /**
+     * Translates the coordinates from center to origin coordinates (based on the object's dimensions)
+     * @param {fabric.Point} center The point which corresponds to center of the object
+     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {fabric.Point}
+     */
+    translateToOriginPoint: function(center, originX, originY) {
+      var p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);
+      if (this.angle) {
+        return fabric.util.rotatePoint(p, center, degreesToRadians(this.angle));
+      }
+      return p;
+    },
+
+    /**
+     * Returns the real center coordinates of the object
+     * @return {fabric.Point}
+     */
+    getCenterPoint: function() {
+      var leftTop = new fabric.Point(this.left, this.top);
+      return this.translateToCenterPoint(leftTop, this.originX, this.originY);
+    },
+
+    /**
+     * Returns the coordinates of the object based on center coordinates
+     * @param {fabric.Point} point The point which corresponds to the originX and originY params
+     * @return {fabric.Point}
+     */
+    // getOriginPoint: function(center) {
+    //   return this.translateToOriginPoint(center, this.originX, this.originY);
+    // },
+
+    /**
+     * Returns the coordinates of the object as if it has a different origin
+     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {fabric.Point}
+     */
+    getPointByOrigin: function(originX, originY) {
+      var center = this.getCenterPoint();
+      return this.translateToOriginPoint(center, originX, originY);
+    },
+
+    /**
+     * Returns the point in local coordinates
+     * @param {fabric.Point} point The point relative to the global coordinate system
+     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {fabric.Point}
+     */
+    toLocalPoint: function(point, originX, originY) {
+      var center = this.getCenterPoint(),
+          p, p2;
+
+      if (typeof originX !== 'undefined' && typeof originY !== 'undefined' ) {
+        p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);
+      }
+      else {
+        p = new fabric.Point(this.left, this.top);
+      }
+
+      p2 = new fabric.Point(point.x, point.y);
+      if (this.angle) {
+        p2 = fabric.util.rotatePoint(p2, center, -degreesToRadians(this.angle));
+      }
+      return p2.subtractEquals(p);
+    },
+
+    /**
+     * Returns the point in global coordinates
+     * @param {fabric.Point} The point relative to the local coordinate system
+     * @return {fabric.Point}
+     */
+    // toGlobalPoint: function(point) {
+    //   return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top));
+    // },
+
+    /**
+     * Sets the position of the object taking into consideration the object's origin
+     * @param {fabric.Point} pos The new position of the object
+     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'
+     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'
+     * @return {void}
+     */
+    setPositionByOrigin: function(pos, originX, originY) {
+      var center = this.translateToCenterPoint(pos, originX, originY),
+          position = this.translateToOriginPoint(center, this.originX, this.originY);
+
+      this.set('left', position.x);
+      this.set('top', position.y);
+    },
+
+    /**
+     * @param {String} to One of 'left', 'center', 'right'
+     */
+    adjustPosition: function(to) {
+      var angle = degreesToRadians(this.angle),
+          hypotFull = this.getWidth(),
+          xFull = Math.cos(angle) * hypotFull,
+          yFull = Math.sin(angle) * hypotFull,
+          offsetFrom, offsetTo;
+
+      //TODO: this function does not consider mixed situation like top, center.
+      if (typeof this.originX === 'string') {
+        offsetFrom = originXOffset[this.originX];
+      }
+      else {
+        offsetFrom = this.originX - 0.5;
+      }
+      if (typeof to === 'string') {
+        offsetTo = originXOffset[to];
+      }
+      else {
+        offsetTo = to - 0.5;
+      }
+      this.left += xFull * (offsetTo - offsetFrom);
+      this.top += yFull * (offsetTo - offsetFrom);
+      this.setCoords();
+      this.originX = to;
+    },
+
+    /**
+     * Sets the origin/position of the object to it's center point
+     * @private
+     * @return {void}
+     */
+    _setOriginToCenter: function() {
+      this._originalOriginX = this.originX;
+      this._originalOriginY = this.originY;
+
+      var center = this.getCenterPoint();
+
+      this.originX = 'center';
+      this.originY = 'center';
+
+      this.left = center.x;
+      this.top = center.y;
+    },
+
+    /**
+     * Resets the origin/position of the object to it's original origin
+     * @private
+     * @return {void}
+     */
+    _resetOrigin: function() {
+      var originPoint = this.translateToOriginPoint(
+        this.getCenterPoint(),
+        this._originalOriginX,
+        this._originalOriginY);
+
+      this.originX = this._originalOriginX;
+      this.originY = this._originalOriginY;
+
+      this.left = originPoint.x;
+      this.top = originPoint.y;
+
+      this._originalOriginX = null;
+      this._originalOriginY = null;
+    },
+
+    /**
+     * @private
+     */
+    _getLeftTopCoords: function() {
+      return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top');
+    }
+  });
+
+})();
+
+
+(function() {
+
+  function getCoords(oCoords) {
+    return [
+      new fabric.Point(oCoords.tl.x, oCoords.tl.y),
+      new fabric.Point(oCoords.tr.x, oCoords.tr.y),
+      new fabric.Point(oCoords.br.x, oCoords.br.y),
+      new fabric.Point(oCoords.bl.x, oCoords.bl.y)
+    ];
+  }
+
+  var degreesToRadians = fabric.util.degreesToRadians,
+      multiplyMatrices = fabric.util.multiplyTransformMatrices;
+
+  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+    /**
+     * Object containing coordinates of object's controls
+     * @type Object
+     * @default
+     */
+    oCoords: null,
+
+    /**
+     * Checks if object intersects with an area formed by 2 points
+     * @param {Object} pointTL top-left point of area
+     * @param {Object} pointBR bottom-right point of area
+     * @return {Boolean} true if object intersects with an area formed by 2 points
+     */
+    intersectsWithRect: function(pointTL, pointBR) {
+      var oCoords = getCoords(this.oCoords),
+          intersection = fabric.Intersection.intersectPolygonRectangle(
+            oCoords,
+            pointTL,
+            pointBR
+          );
+      return intersection.status === 'Intersection';
+    },
+
+    /**
+     * Checks if object intersects with another object
+     * @param {Object} other Object to test
+     * @return {Boolean} true if object intersects with another object
+     */
+    intersectsWithObject: function(other) {
+      var intersection = fabric.Intersection.intersectPolygonPolygon(
+            getCoords(this.oCoords),
+            getCoords(other.oCoords)
+          );
+
+      return intersection.status === 'Intersection'
+        || other.isContainedWithinObject(this)
+        || this.isContainedWithinObject(other);
+    },
+
+    /**
+     * Checks if object is fully contained within area of another object
+     * @param {Object} other Object to test
+     * @return {Boolean} true if object is fully contained within area of another object
+     */
+    isContainedWithinObject: function(other) {
+      var points = getCoords(this.oCoords),
+          i = 0;
+      for (; i < 4; i++) {
+        if (!other.containsPoint(points[i])) {
+          return false;
+        }
+      }
+      return true;
+    },
+
+    /**
+     * Checks if object is fully contained within area formed by 2 points
+     * @param {Object} pointTL top-left point of area
+     * @param {Object} pointBR bottom-right point of area
+     * @return {Boolean} true if object is fully contained within area formed by 2 points
+     */
+    isContainedWithinRect: function(pointTL, pointBR) {
+      var boundingRect = this.getBoundingRect();
+
+      return (
+        boundingRect.left >= pointTL.x &&
+        boundingRect.left + boundingRect.width <= pointBR.x &&
+        boundingRect.top >= pointTL.y &&
+        boundingRect.top + boundingRect.height <= pointBR.y
+      );
+    },
+
+    /**
+     * Checks if point is inside the object
+     * @param {fabric.Point} point Point to check against
+     * @return {Boolean} true if point is inside the object
+     */
+    containsPoint: function(point) {
+      if (!this.oCoords) {
+        this.setCoords();
+      }
+      var lines = this._getImageLines(this.oCoords),
+          xPoints = this._findCrossPoints(point, lines);
+
+      // if xPoints is odd then point is inside the object
+      return (xPoints !== 0 && xPoints % 2 === 1);
+    },
+
+    /**
+     * Method that returns an object with the object edges in it, given the coordinates of the corners
+     * @private
+     * @param {Object} oCoords Coordinates of the object corners
+     */
+    _getImageLines: function(oCoords) {
+      return {
+        topline: {
+          o: oCoords.tl,
+          d: oCoords.tr
+        },
+        rightline: {
+          o: oCoords.tr,
+          d: oCoords.br
+        },
+        bottomline: {
+          o: oCoords.br,
+          d: oCoords.bl
+        },
+        leftline: {
+          o: oCoords.bl,
+          d: oCoords.tl
+        }
+      };
+    },
+
+    /**
+     * Helper method to determine how many cross points are between the 4 object edges
+     * and the horizontal line determined by a point on canvas
+     * @private
+     * @param {fabric.Point} point Point to check
+     * @param {Object} oCoords Coordinates of the object being evaluated
+     */
+     // remove yi, not used but left code here just in case.
+    _findCrossPoints: function(point, oCoords) {
+      var b1, b2, a1, a2, xi, // yi,
+          xcount = 0,
+          iLine;
+
+      for (var lineKey in oCoords) {
+        iLine = oCoords[lineKey];
+        // optimisation 1: line below point. no cross
+        if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) {
+          continue;
+        }
+        // optimisation 2: line above point. no cross
+        if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) {
+          continue;
+        }
+        // optimisation 3: vertical line case
+        if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) {
+          xi = iLine.o.x;
+          // yi = point.y;
+        }
+        // calculate the intersection point
+        else {
+          b1 = 0;
+          b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x);
+          a1 = point.y - b1 * point.x;
+          a2 = iLine.o.y - b2 * iLine.o.x;
+
+          xi = -(a1 - a2) / (b1 - b2);
+          // yi = a1 + b1 * xi;
+        }
+        // dont count xi < point.x cases
+        if (xi >= point.x) {
+          xcount += 1;
+        }
+        // optimisation 4: specific for square images
+        if (xcount === 2) {
+          break;
+        }
+      }
+      return xcount;
+    },
+
+    /**
+     * Returns width of an object's bounding rectangle
+     * @deprecated since 1.0.4
+     * @return {Number} width value
+     */
+    getBoundingRectWidth: function() {
+      return this.getBoundingRect().width;
+    },
+
+    /**
+     * Returns height of an object's bounding rectangle
+     * @deprecated since 1.0.4
+     * @return {Number} height value
+     */
+    getBoundingRectHeight: function() {
+      return this.getBoundingRect().height;
+    },
+
+    /**
+     * Returns coordinates of object's bounding rectangle (left, top, width, height)
+     * @return {Object} Object with left, top, width, height properties
+     */
+    getBoundingRect: function() {
+      this.oCoords || this.setCoords();
+      return fabric.util.makeBoundingBoxFromPoints([
+        this.oCoords.tl,
+        this.oCoords.tr,
+        this.oCoords.br,
+        this.oCoords.bl
+      ]);
+    },
+
+    /**
+     * Returns width of an object bounding box counting transformations
+     * @return {Number} width value
+     */
+    getWidth: function() {
+      return this._getTransformedDimensions().x;
+    },
+
+    /**
+     * Returns height of an object bounding box counting transformations
+     * to be renamed in 2.0
+     * @return {Number} height value
+     */
+    getHeight: function() {
+      return this._getTransformedDimensions().y;
+    },
+
+    /**
+     * Makes sure the scale is valid and modifies it if necessary
+     * @private
+     * @param {Number} value
+     * @return {Number}
+     */
+    _constrainScale: function(value) {
+      if (Math.abs(value) < this.minScaleLimit) {
+        if (value < 0) {
+          return -this.minScaleLimit;
+        }
+        else {
+          return this.minScaleLimit;
+        }
+      }
+      return value;
+    },
+
+    /**
+     * Scales an object (equally by x and y)
+     * @param {Number} value Scale factor
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    scale: function(value) {
+      value = this._constrainScale(value);
+
+      if (value < 0) {
+        this.flipX = !this.flipX;
+        this.flipY = !this.flipY;
+        value *= -1;
+      }
+
+      this.scaleX = value;
+      this.scaleY = value;
+      this.setCoords();
+      return this;
+    },
+
+    /**
+     * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)
+     * @param {Number} value New width value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    scaleToWidth: function(value) {
+      // adjust to bounding rect factor so that rotated shapes would fit as well
+      var boundingRectFactor = this.getBoundingRect().width / this.getWidth();
+      return this.scale(value / this.width / boundingRectFactor);
+    },
+
+    /**
+     * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)
+     * @param {Number} value New height value
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    scaleToHeight: function(value) {
+      // adjust to bounding rect factor so that rotated shapes would fit as well
+      var boundingRectFactor = this.getBoundingRect().height / this.getHeight();
+      return this.scale(value / this.height / boundingRectFactor);
+    },
+
+    /**
+     * Sets corner position coordinates based on current angle, width and height
+     * See https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setCoords: function() {
+      var theta = degreesToRadians(this.angle),
+          vpt = this.getViewportTransform(),
+          dim = this._calculateCurrentDimensions(),
+          currentWidth = dim.x, currentHeight = dim.y;
+
+      // If width is negative, make postive. Fixes path selection issue
+      if (currentWidth < 0) {
+        currentWidth = Math.abs(currentWidth);
+      }
+
+      var sinTh = Math.sin(theta),
+          cosTh = Math.cos(theta),
+          _angle = currentWidth > 0 ? Math.atan(currentHeight / currentWidth) : 0,
+          _hypotenuse = (currentWidth / Math.cos(_angle)) / 2,
+          offsetX = Math.cos(_angle + theta) * _hypotenuse,
+          offsetY = Math.sin(_angle + theta) * _hypotenuse,
+
+          // offset added for rotate and scale actions
+          coords = fabric.util.transformPoint(this.getCenterPoint(), vpt),
+          tl  = new fabric.Point(coords.x - offsetX, coords.y - offsetY),
+          tr  = new fabric.Point(tl.x + (currentWidth * cosTh), tl.y + (currentWidth * sinTh)),
+          bl  = new fabric.Point(tl.x - (currentHeight * sinTh), tl.y + (currentHeight * cosTh)),
+          br  = new fabric.Point(coords.x + offsetX, coords.y + offsetY),
+          ml  = new fabric.Point((tl.x + bl.x) / 2, (tl.y + bl.y) / 2),
+          mt  = new fabric.Point((tr.x + tl.x) / 2, (tr.y + tl.y) / 2),
+          mr  = new fabric.Point((br.x + tr.x) / 2, (br.y + tr.y) / 2),
+          mb  = new fabric.Point((br.x + bl.x) / 2, (br.y + bl.y) / 2),
+          mtr = new fabric.Point(mt.x + sinTh * this.rotatingPointOffset, mt.y - cosTh * this.rotatingPointOffset);
+      // debugging
+
+      /* setTimeout(function() {
+         canvas.contextTop.fillStyle = 'green';
+         canvas.contextTop.fillRect(mb.x, mb.y, 3, 3);
+         canvas.contextTop.fillRect(bl.x, bl.y, 3, 3);
+         canvas.contextTop.fillRect(br.x, br.y, 3, 3);
+         canvas.contextTop.fillRect(tl.x, tl.y, 3, 3);
+         canvas.contextTop.fillRect(tr.x, tr.y, 3, 3);
+         canvas.contextTop.fillRect(ml.x, ml.y, 3, 3);
+         canvas.contextTop.fillRect(mr.x, mr.y, 3, 3);
+         canvas.contextTop.fillRect(mt.x, mt.y, 3, 3);
+         canvas.contextTop.fillRect(mtr.x, mtr.y, 3, 3);
+       }, 50); */
+
+      this.oCoords = {
+        // corners
+        tl: tl, tr: tr, br: br, bl: bl,
+        // middle
+        ml: ml, mt: mt, mr: mr, mb: mb,
+        // rotating point
+        mtr: mtr
+      };
+
+      // set coordinates of the draggable boxes in the corners used to scale/rotate the image
+      this._setCornerCoords && this._setCornerCoords();
+
+      return this;
+    },
+
+    /*
+     * calculate rotation matrix of an object
+     * @return {Array} rotation matrix for the object
+     */
+    _calcRotateMatrix: function() {
+      if (this.angle) {
+        var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta);
+        return [cos, sin, -sin, cos, 0, 0];
+      }
+      return [1, 0, 0, 1, 0, 0];
+    },
+
+    /*
+     * calculate trasform Matrix that represent current transformation from
+     * object properties.
+     * @return {Array} matrix Transform Matrix for the object
+     */
+    calcTransformMatrix: function() {
+      var center = this.getCenterPoint(),
+          translateMatrix = [1, 0, 0, 1, center.x, center.y],
+          rotateMatrix = this._calcRotateMatrix(),
+          dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true),
+          matrix = this.group ? this.group.calcTransformMatrix() : [1, 0, 0, 1, 0, 0];
+      matrix = multiplyMatrices(matrix, translateMatrix);
+      matrix = multiplyMatrices(matrix, rotateMatrix);
+      matrix = multiplyMatrices(matrix, dimensionMatrix);
+      return matrix;
+    },
+
+    _calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
+      var skewMatrixX = [1, 0, Math.tan(degreesToRadians(skewX)), 1],
+          skewMatrixY = [1, Math.tan(degreesToRadians(skewY)), 0, 1],
+          scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1),
+          scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1),
+          scaleMatrix = [scaleX, 0, 0, scaleY],
+          m = multiplyMatrices(scaleMatrix, skewMatrixX, true);
+      return multiplyMatrices(m, skewMatrixY, true);
+    }
+  });
+})();
+
+
+fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+  /**
+   * Moves an object to the bottom of the stack of drawn objects
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  sendToBack: function() {
+    if (this.group) {
+      fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);
+    }
+    else {
+      this.canvas.sendToBack(this);
+    }
+    return this;
+  },
+
+  /**
+   * Moves an object to the top of the stack of drawn objects
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  bringToFront: function() {
+    if (this.group) {
+      fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);
+    }
+    else {
+      this.canvas.bringToFront(this);
+    }
+    return this;
+  },
+
+  /**
+   * Moves an object down in stack of drawn objects
+   * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  sendBackwards: function(intersecting) {
+    if (this.group) {
+      fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);
+    }
+    else {
+      this.canvas.sendBackwards(this, intersecting);
+    }
+    return this;
+  },
+
+  /**
+   * Moves an object up in stack of drawn objects
+   * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  bringForward: function(intersecting) {
+    if (this.group) {
+      fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);
+    }
+    else {
+      this.canvas.bringForward(this, intersecting);
+    }
+    return this;
+  },
+
+  /**
+   * Moves an object to specified level in stack of drawn objects
+   * @param {Number} index New position of object
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  moveTo: function(index) {
+    if (this.group) {
+      fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);
+    }
+    else {
+      this.canvas.moveTo(this, index);
+    }
+    return this;
+  }
+});
+
+
+/* _TO_SVG_START_ */
+(function() {
+
+  function getSvgColorString(prop, value) {
+    if (!value) {
+      return prop + ': none; ';
+    }
+    else if (value.toLive) {
+      return prop + ': url(#SVGID_' + value.id + '); ';
+    }
+    else {
+      var color = new fabric.Color(value),
+          str = prop + ': ' + color.toRgb() + '; ',
+          opacity = color.getAlpha();
+      if (opacity !== 1) {
+        //change the color in rgb + opacity
+        str += prop + '-opacity: ' + opacity.toString() + '; ';
+      }
+      return str;
+    }
+  }
+
+  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+    /**
+     * Returns styles-string for svg-export
+     * @param {Boolean} skipShadow a boolean to skip shadow filter output
+     * @return {String}
+     */
+    getSvgStyles: function(skipShadow) {
+
+      var fillRule = this.fillRule,
+          strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
+          strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',
+          strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',
+          strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',
+          strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',
+          opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',
+          visibility = this.visible ? '' : ' visibility: hidden;',
+          filter = skipShadow ? '' : this.getSvgFilter(),
+          fill = getSvgColorString('fill', this.fill),
+          stroke = getSvgColorString('stroke', this.stroke);
+
+      return [
+        stroke,
+        'stroke-width: ', strokeWidth, '; ',
+        'stroke-dasharray: ', strokeDashArray, '; ',
+        'stroke-linecap: ', strokeLineCap, '; ',
+        'stroke-linejoin: ', strokeLineJoin, '; ',
+        'stroke-miterlimit: ', strokeMiterLimit, '; ',
+        fill,
+        'fill-rule: ', fillRule, '; ',
+        'opacity: ', opacity, ';',
+        filter,
+        visibility
+      ].join('');
+    },
+
+    /**
+     * Returns filter for svg shadow
+     * @return {String}
+     */
+    getSvgFilter: function() {
+      return this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';
+    },
+
+    /**
+     * Returns id attribute for svg output
+     * @return {String}
+     */
+    getSvgId: function() {
+      return this.id ? 'id="' + this.id + '" ' : '';
+    },
+
+    /**
+     * Returns transform-string for svg-export
+     * @return {String}
+     */
+    getSvgTransform: function() {
+      if (this.group && this.group.type === 'path-group') {
+        return '';
+      }
+      var toFixed = fabric.util.toFixed,
+          angle = this.getAngle(),
+          skewX = (this.getSkewX() % 360),
+          skewY = (this.getSkewY() % 360),
+          center = this.getCenterPoint(),
+
+          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
+
+          translatePart = this.type === 'path-group' ? '' : 'translate(' +
+                            toFixed(center.x, NUM_FRACTION_DIGITS) +
+                            ' ' +
+                            toFixed(center.y, NUM_FRACTION_DIGITS) +
+                          ')',
+
+          anglePart = angle !== 0
+            ? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')')
+            : '',
+
+          scalePart = (this.scaleX === 1 && this.scaleY === 1)
+            ? '' :
+            (' scale(' +
+              toFixed(this.scaleX, NUM_FRACTION_DIGITS) +
+              ' ' +
+              toFixed(this.scaleY, NUM_FRACTION_DIGITS) +
+            ')'),
+
+          skewXPart = skewX !== 0 ? ' skewX(' + toFixed(skewX, NUM_FRACTION_DIGITS) + ')' : '',
+
+          skewYPart = skewY !== 0 ? ' skewY(' + toFixed(skewY, NUM_FRACTION_DIGITS) + ')' : '',
+
+          addTranslateX = this.type === 'path-group' ? this.width : 0,
+
+          flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '',
+
+          addTranslateY = this.type === 'path-group' ? this.height : 0,
+
+          flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';
+
+      return [
+        translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart
+      ].join('');
+    },
+
+    /**
+     * Returns transform-string for svg-export from the transform matrix of single elements
+     * @return {String}
+     */
+    getSvgTransformMatrix: function() {
+      return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ') ' : '';
+    },
+
+    /**
+     * @private
+     */
+    _createBaseSVGMarkup: function() {
+      var markup = [];
+
+      if (this.fill && this.fill.toLive) {
+        markup.push(this.fill.toSVG(this, false));
+      }
+      if (this.stroke && this.stroke.toLive) {
+        markup.push(this.stroke.toSVG(this, false));
+      }
+      if (this.shadow) {
+        markup.push(this.shadow.toSVG(this));
+      }
+      return markup;
+    }
+  });
+})();
+/* _TO_SVG_END_ */
+
+
+(function() {
+
+  var extend = fabric.util.object.extend;
+
+  /*
+    Depends on `stateProperties`
+  */
+  function saveProps(origin, destination, props) {
+    var tmpObj = { }, deep = true;
+    props.forEach(function(prop) {
+      tmpObj[prop] = origin[prop];
+    });
+    extend(origin[destination], tmpObj, deep);
+  }
+
+  function _isEqual(origValue, currentValue) {
+    if (!fabric.isLikelyNode && origValue instanceof Element) {
+      // avoid checking deep html elements
+      return origValue === currentValue;
+    }
+    else if (origValue instanceof Array) {
+      if (origValue.length !== currentValue.length) {
+        return false
+      }
+      var _currentValue = currentValue.concat().sort(),
+          _origValue = origValue.concat().sort();
+      return !_origValue.some(function(v, i) {
+        return !_isEqual(_currentValue[i], v);
+      });
+    }
+    else if (origValue instanceof Object) {
+      for (var key in origValue) {
+        if (!_isEqual(origValue[key], currentValue[key])) {
+          return false;
+        }
+      }
+      return true;
+    }
+    else {
+      return origValue === currentValue;
+    }
+  }
+
+
+  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+    /**
+     * Returns true if object state (one of its state properties) was changed
+     * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called
+     */
+    hasStateChanged: function() {
+      return !_isEqual(this.originalState, this);
+    },
+
+    /**
+     * Saves state of an object
+     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state
+     * @return {fabric.Object} thisArg
+     */
+    saveState: function(options) {
+      saveProps(this, 'originalState', this.stateProperties);
+      if (options && options.stateProperties) {
+        saveProps(this, 'originalState', options.stateProperties);
+      }
+      return this;
+    },
+
+    /**
+     * Setups state of an object
+     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state
+     * @return {fabric.Object} thisArg
+     */
+    setupState: function(options) {
+      this.originalState = { };
+      this.saveState(options);
+      return this;
+    }
+  });
+})();
+
+
+(function() {
+
+  var degreesToRadians = fabric.util.degreesToRadians,
+      /* eslint-disable camelcase */
+      isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };
+      /* eslint-enable camelcase */
+  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+    /**
+     * The object interactivity controls.
+     * @private
+     */
+    _controlsVisibility: null,
+
+    /**
+     * Determines which corner has been clicked
+     * @private
+     * @param {Object} pointer The pointer indicating the mouse position
+     * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
+     */
+    _findTargetCorner: function(pointer) {
+      if (!this.hasControls || !this.active) {
+        return false;
+      }
+
+      var ex = pointer.x,
+          ey = pointer.y,
+          xPoints,
+          lines;
+      this.__corner = 0;
+      for (var i in this.oCoords) {
+
+        if (!this.isControlVisible(i)) {
+          continue;
+        }
+
+        if (i === 'mtr' && !this.hasRotatingPoint) {
+          continue;
+        }
+
+        if (this.get('lockUniScaling') &&
+           (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
+          continue;
+        }
+
+        lines = this._getImageLines(this.oCoords[i].corner);
+
+        // debugging
+
+        // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
+        // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);
+
+        // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);
+        // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);
+
+        // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);
+        // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);
+
+        // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);
+        // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);
+
+        xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);
+        if (xPoints !== 0 && xPoints % 2 === 1) {
+          this.__corner = i;
+          return i;
+        }
+      }
+      return false;
+    },
+
+    /**
+     * Sets the coordinates of the draggable boxes in the corners of
+     * the image used to scale/rotate it.
+     * @private
+     */
+    _setCornerCoords: function() {
+      var coords = this.oCoords,
+          newTheta = degreesToRadians(45 - this.angle),
+          /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */
+          /* 0.707106 stands for sqrt(2)/2 */
+          cornerHypotenuse = this.cornerSize * 0.707106,
+          cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),
+          sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),
+          x, y;
+
+      for (var point in coords) {
+        x = coords[point].x;
+        y = coords[point].y;
+        coords[point].corner = {
+          tl: {
+            x: x - sinHalfOffset,
+            y: y - cosHalfOffset
+          },
+          tr: {
+            x: x + cosHalfOffset,
+            y: y - sinHalfOffset
+          },
+          bl: {
+            x: x - cosHalfOffset,
+            y: y + sinHalfOffset
+          },
+          br: {
+            x: x + sinHalfOffset,
+            y: y + cosHalfOffset
+          }
+        };
+      }
+    },
+
+    /*
+     * Calculate object dimensions from its properties
+     * @private
+     */
+    _getNonTransformedDimensions: function() {
+      var strokeWidth = this.strokeWidth,
+          w = this.width,
+          h = this.height,
+          addStrokeToW = true,
+          addStrokeToH = true;
+
+      if (this.type === 'line' && this.strokeLineCap === 'butt') {
+        addStrokeToH = w;
+        addStrokeToW = h;
+      }
+
+      if (addStrokeToH) {
+        h += h < 0 ? -strokeWidth : strokeWidth;
+      }
+
+      if (addStrokeToW) {
+        w += w < 0 ? -strokeWidth : strokeWidth;
+      }
+
+      return { x: w, y: h };
+    },
+
+    /*
+     * @private
+     */
+    _getTransformedDimensions: function(skewX, skewY) {
+      if (typeof skewX === 'undefined') {
+        skewX = this.skewX;
+      }
+      if (typeof skewY === 'undefined') {
+        skewY = this.skewY;
+      }
+      var dimensions = this._getNonTransformedDimensions(),
+          dimX = dimensions.x / 2, dimY = dimensions.y / 2,
+          points = [
+            {
+              x: -dimX,
+              y: -dimY
+            },
+            {
+              x: dimX,
+              y: -dimY
+            },
+            {
+              x: -dimX,
+              y: dimY
+            },
+            {
+              x: dimX,
+              y: dimY
+            }],
+          i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false),
+          bbox;
+      for (i = 0; i < points.length; i++) {
+        points[i] = fabric.util.transformPoint(points[i], transformMatrix);
+      }
+      bbox = fabric.util.makeBoundingBoxFromPoints(points);
+      return { x: bbox.width, y: bbox.height };
+    },
+
+    /*
+     * private
+     */
+    _calculateCurrentDimensions: function()  {
+      var vpt = this.getViewportTransform(),
+          dim = this._getTransformedDimensions(),
+          w = dim.x, h = dim.y,
+          p = fabric.util.transformPoint(new fabric.Point(w, h), vpt, true);
+
+      return p.scalarAdd(2 * this.padding);
+    },
+
+    /**
+     * Draws a colored layer behind the object, inside its selection borders.
+     * Requires public options: padding, selectionBackgroundColor
+     * this function is called when the context is transformed
+     * @param {CanvasRenderingContext2D} ctx Context to draw on
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    drawSelectionBackground: function(ctx) {
+      if (!this.selectionBackgroundColor || this.group || !this.active) {
+        return this;
+      }
+      ctx.save();
+      var center = this.getCenterPoint(), wh = this._calculateCurrentDimensions(),
+          vpt = this.canvas.viewportTransform;
+      ctx.translate(center.x, center.y);
+      ctx.scale(1 / vpt[0], 1 / vpt[3]);
+      ctx.rotate(degreesToRadians(this.angle));
+      ctx.fillStyle = this.selectionBackgroundColor;
+      ctx.fillRect(-wh.x / 2, -wh.y / 2, wh.x, wh.y);
+      ctx.restore();
+      return this;
+    },
+
+    /**
+     * Draws borders of an object's bounding box.
+     * Requires public properties: width, height
+     * Requires public options: padding, borderColor
+     * @param {CanvasRenderingContext2D} ctx Context to draw on
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    drawBorders: function(ctx) {
+      if (!this.hasBorders) {
+        return this;
+      }
+
+      var wh = this._calculateCurrentDimensions(),
+          strokeWidth = 1 / this.borderScaleFactor,
+          width = wh.x + strokeWidth,
+          height = wh.y + strokeWidth;
+
+      ctx.save();
+      ctx.strokeStyle = this.borderColor;
+      this._setLineDash(ctx, this.borderDashArray, null);
+
+      ctx.strokeRect(
+        -width / 2,
+        -height / 2,
+        width,
+        height
+      );
+
+      if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {
+
+        var rotateHeight = -height / 2;
+
+        ctx.beginPath();
+        ctx.moveTo(0, rotateHeight);
+        ctx.lineTo(0, rotateHeight - this.rotatingPointOffset);
+        ctx.closePath();
+        ctx.stroke();
+      }
+
+      ctx.restore();
+      return this;
+    },
+
+    /**
+     * Draws borders of an object's bounding box when it is inside a group.
+     * Requires public properties: width, height
+     * Requires public options: padding, borderColor
+     * @param {CanvasRenderingContext2D} ctx Context to draw on
+     * @param {object} options object representing current object parameters
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    drawBordersInGroup: function(ctx, options) {
+      if (!this.hasBorders) {
+        return this;
+      }
+
+      var p = this._getNonTransformedDimensions(),
+          matrix = fabric.util.customTransformMatrix(options.scaleX, options.scaleY, options.skewX),
+          wh = fabric.util.transformPoint(p, matrix),
+          strokeWidth = 1 / this.borderScaleFactor,
+          width = wh.x + strokeWidth + 2 * this.padding,
+          height = wh.y + strokeWidth + 2 * this.padding;
+
+      ctx.save();
+      this._setLineDash(ctx, this.borderDashArray, null);
+      ctx.strokeStyle = this.borderColor;
+
+      ctx.strokeRect(
+        -width / 2,
+        -height / 2,
+        width,
+        height
+      );
+
+      ctx.restore();
+      return this;
+    },
+
+    /**
+     * Draws corners of an object's bounding box.
+     * Requires public properties: width, height
+     * Requires public options: cornerSize, padding
+     * @param {CanvasRenderingContext2D} ctx Context to draw on
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    drawControls: function(ctx) {
+      if (!this.hasControls) {
+        return this;
+      }
+
+      var wh = this._calculateCurrentDimensions(),
+          width = wh.x,
+          height = wh.y,
+          scaleOffset = this.cornerSize,
+          left = -(width + scaleOffset) / 2,
+          top = -(height + scaleOffset) / 2,
+          methodName = this.transparentCorners ? 'stroke' : 'fill';
+
+      ctx.save();
+      ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
+      if (!this.transparentCorners) {
+        ctx.strokeStyle = this.cornerStrokeColor;
+      }
+      this._setLineDash(ctx, this.cornerDashArray, null);
+
+      // top-left
+      this._drawControl('tl', ctx, methodName,
+        left,
+        top);
+
+      // top-right
+      this._drawControl('tr', ctx, methodName,
+        left + width,
+        top);
+
+      // bottom-left
+      this._drawControl('bl', ctx, methodName,
+        left,
+        top + height);
+
+      // bottom-right
+      this._drawControl('br', ctx, methodName,
+        left + width,
+        top + height);
+
+      if (!this.get('lockUniScaling')) {
+
+        // middle-top
+        this._drawControl('mt', ctx, methodName,
+          left + width / 2,
+          top);
+
+        // middle-bottom
+        this._drawControl('mb', ctx, methodName,
+          left + width / 2,
+          top + height);
+
+        // middle-right
+        this._drawControl('mr', ctx, methodName,
+          left + width,
+          top + height / 2);
+
+        // middle-left
+        this._drawControl('ml', ctx, methodName,
+          left,
+          top + height / 2);
+      }
+
+      // middle-top-rotate
+      if (this.hasRotatingPoint) {
+        this._drawControl('mtr', ctx, methodName,
+          left + width / 2,
+          top - this.rotatingPointOffset);
+      }
+
+      ctx.restore();
+
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _drawControl: function(control, ctx, methodName, left, top) {
+      if (!this.isControlVisible(control)) {
+        return;
+      }
+      var size = this.cornerSize, stroke = !this.transparentCorners && this.cornerStrokeColor;
+      switch (this.cornerStyle) {
+        case 'circle':
+          ctx.beginPath();
+          ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI, false);
+          ctx[methodName]();
+          if (stroke) {
+            ctx.stroke();
+          }
+          break;
+        default:
+          isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);
+          ctx[methodName + 'Rect'](left, top, size, size);
+          if (stroke) {
+            ctx.strokeRect(left, top, size, size);
+          }
+      }
+    },
+
+    /**
+     * Returns true if the specified control is visible, false otherwise.
+     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
+     * @returns {Boolean} true if the specified control is visible, false otherwise
+     */
+    isControlVisible: function(controlName) {
+      return this._getControlsVisibility()[controlName];
+    },
+
+    /**
+     * Sets the visibility of the specified control.
+     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
+     * @param {Boolean} visible true to set the specified control visible, false otherwise
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setControlVisible: function(controlName, visible) {
+      this._getControlsVisibility()[controlName] = visible;
+      return this;
+    },
+
+    /**
+     * Sets the visibility state of object controls.
+     * @param {Object} [options] Options object
+     * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it
+     * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it
+     * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it
+     * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it
+     * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it
+     * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it
+     * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it
+     * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it
+     * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it
+     * @return {fabric.Object} thisArg
+     * @chainable
+     */
+    setControlsVisibility: function(options) {
+      options || (options = { });
+
+      for (var p in options) {
+        this.setControlVisible(p, options[p]);
+      }
+      return this;
+    },
+
+    /**
+     * Returns the instance of the control visibility set for this object.
+     * @private
+     * @returns {Object}
+     */
+    _getControlsVisibility: function() {
+      if (!this._controlsVisibility) {
+        this._controlsVisibility = {
+          tl: true,
+          tr: true,
+          br: true,
+          bl: true,
+          ml: true,
+          mt: true,
+          mr: true,
+          mb: true,
+          mtr: true
+        };
+      }
+      return this._controlsVisibility;
+    }
+  });
+})();
+
+
+fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
+
+  /**
+   * Animation duration (in ms) for fx* methods
+   * @type Number
+   * @default
+   */
+  FX_DURATION: 500,
+
+  /**
+   * Centers object horizontally with animation.
+   * @param {fabric.Object} object Object to center
+   * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
+   * @param {Function} [callbacks.onComplete] Invoked on completion
+   * @param {Function} [callbacks.onChange] Invoked on every step of animation
+   * @return {fabric.Canvas} thisArg
+   * @chainable
+   */
+  fxCenterObjectH: function (object, callbacks) {
+    callbacks = callbacks || { };
+
+    var empty = function() { },
+        onComplete = callbacks.onComplete || empty,
+        onChange = callbacks.onChange || empty,
+        _this = this;
+
+    fabric.util.animate({
+      startValue: object.get('left'),
+      endValue: this.getCenter().left,
+      duration: this.FX_DURATION,
+      onChange: function(value) {
+        object.set('left', value);
+        _this.renderAll();
+        onChange();
+      },
+      onComplete: function() {
+        object.setCoords();
+        onComplete();
+      }
+    });
+
+    return this;
+  },
+
+  /**
+   * Centers object vertically with animation.
+   * @param {fabric.Object} object Object to center
+   * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
+   * @param {Function} [callbacks.onComplete] Invoked on completion
+   * @param {Function} [callbacks.onChange] Invoked on every step of animation
+   * @return {fabric.Canvas} thisArg
+   * @chainable
+   */
+  fxCenterObjectV: function (object, callbacks) {
+    callbacks = callbacks || { };
+
+    var empty = function() { },
+        onComplete = callbacks.onComplete || empty,
+        onChange = callbacks.onChange || empty,
+        _this = this;
+
+    fabric.util.animate({
+      startValue: object.get('top'),
+      endValue: this.getCenter().top,
+      duration: this.FX_DURATION,
+      onChange: function(value) {
+        object.set('top', value);
+        _this.renderAll();
+        onChange();
+      },
+      onComplete: function() {
+        object.setCoords();
+        onComplete();
+      }
+    });
+
+    return this;
+  },
+
+  /**
+   * Same as `fabric.Canvas#remove` but animated
+   * @param {fabric.Object} object Object to remove
+   * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
+   * @param {Function} [callbacks.onComplete] Invoked on completion
+   * @param {Function} [callbacks.onChange] Invoked on every step of animation
+   * @return {fabric.Canvas} thisArg
+   * @chainable
+   */
+  fxRemove: function (object, callbacks) {
+    callbacks = callbacks || { };
+
+    var empty = function() { },
+        onComplete = callbacks.onComplete || empty,
+        onChange = callbacks.onChange || empty,
+        _this = this;
+
+    fabric.util.animate({
+      startValue: object.get('opacity'),
+      endValue: 0,
+      duration: this.FX_DURATION,
+      onStart: function() {
+        object.set('active', false);
+      },
+      onChange: function(value) {
+        object.set('opacity', value);
+        _this.renderAll();
+        onChange();
+      },
+      onComplete: function () {
+        _this.remove(object);
+        onComplete();
+      }
+    });
+
+    return this;
+  }
+});
+
+fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+  /**
+   * Animates object's properties
+   * @param {String|Object} property Property to animate (if string) or properties to animate (if object)
+   * @param {Number|Object} value Value to animate property to (if string was given first) or options object
+   * @return {fabric.Object} thisArg
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}
+   * @chainable
+   *
+   * As object — multiple properties
+   *
+   * object.animate({ left: ..., top: ... });
+   * object.animate({ left: ..., top: ... }, { duration: ... });
+   *
+   * As string — one property
+   *
+   * object.animate('left', ...);
+   * object.animate('left', { duration: ... });
+   *
+   */
+  animate: function() {
+    if (arguments[0] && typeof arguments[0] === 'object') {
+      var propsToAnimate = [], prop, skipCallbacks;
+      for (prop in arguments[0]) {
+        propsToAnimate.push(prop);
+      }
+      for (var i = 0, len = propsToAnimate.length; i < len; i++) {
+        prop = propsToAnimate[i];
+        skipCallbacks = i !== len - 1;
+        this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);
+      }
+    }
+    else {
+      this._animate.apply(this, arguments);
+    }
+    return this;
+  },
+
+  /**
+   * @private
+   * @param {String} property Property to animate
+   * @param {String} to Value to animate to
+   * @param {Object} [options] Options object
+   * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked
+   */
+  _animate: function(property, to, options, skipCallbacks) {
+    var _this = this, propPair;
+
+    to = to.toString();
+
+    if (!options) {
+      options = { };
+    }
+    else {
+      options = fabric.util.object.clone(options);
+    }
+
+    if (~property.indexOf('.')) {
+      propPair = property.split('.');
+    }
+
+    var currentValue = propPair
+      ? this.get(propPair[0])[propPair[1]]
+      : this.get(property);
+
+    if (!('from' in options)) {
+      options.from = currentValue;
+    }
+
+    if (~to.indexOf('=')) {
+      to = currentValue + parseFloat(to.replace('=', ''));
+    }
+    else {
+      to = parseFloat(to);
+    }
+
+    fabric.util.animate({
+      startValue: options.from,
+      endValue: to,
+      byValue: options.by,
+      easing: options.easing,
+      duration: options.duration,
+      abort: options.abort && function() {
+        return options.abort.call(_this);
+      },
+      onChange: function(value) {
+        if (propPair) {
+          _this[propPair[0]][propPair[1]] = value;
+        }
+        else {
+          _this.set(property, value);
+        }
+        if (skipCallbacks) {
+          return;
+        }
+        options.onChange && options.onChange();
+      },
+      onComplete: function() {
+        if (skipCallbacks) {
+          return;
+        }
+
+        _this.setCoords();
+        options.onComplete && options.onComplete();
+      }
+    });
+  }
+});
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 },
+      supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
+
+  if (fabric.Line) {
+    fabric.warn('fabric.Line is already defined');
+    return;
+  }
+
+  /**
+   * Line class
+   * @class fabric.Line
+   * @extends fabric.Object
+   * @see {@link fabric.Line#initialize} for constructor definition
+   */
+  fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'line',
+
+    /**
+     * x value or first line edge
+     * @type Number
+     * @default
+     */
+    x1: 0,
+
+    /**
+     * y value or first line edge
+     * @type Number
+     * @default
+     */
+    y1: 0,
+
+    /**
+     * x value or second line edge
+     * @type Number
+     * @default
+     */
+    x2: 0,
+
+    /**
+     * y value or second line edge
+     * @type Number
+     * @default
+     */
+    y2: 0,
+
+    /**
+     * Constructor
+     * @param {Array} [points] Array of points
+     * @param {Object} [options] Options object
+     * @return {fabric.Line} thisArg
+     */
+    initialize: function(points, options) {
+      options = options || { };
+
+      if (!points) {
+        points = [0, 0, 0, 0];
+      }
+
+      this.callSuper('initialize', options);
+
+      this.set('x1', points[0]);
+      this.set('y1', points[1]);
+      this.set('x2', points[2]);
+      this.set('y2', points[3]);
+
+      this._setWidthHeight(options);
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options
+     */
+    _setWidthHeight: function(options) {
+      options || (options = { });
+
+      this.width = Math.abs(this.x2 - this.x1);
+      this.height = Math.abs(this.y2 - this.y1);
+
+      this.left = 'left' in options
+        ? options.left
+        : this._getLeftToOriginX();
+
+      this.top = 'top' in options
+        ? options.top
+        : this._getTopToOriginY();
+    },
+
+    /**
+     * @private
+     * @param {String} key
+     * @param {*} value
+     */
+    _set: function(key, value) {
+      this.callSuper('_set', key, value);
+      if (typeof coordProps[key] !== 'undefined') {
+        this._setWidthHeight();
+      }
+      return this;
+    },
+
+    /**
+     * @private
+     * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line.
+     */
+    _getLeftToOriginX: makeEdgeToOriginGetter(
+      { // property names
+        origin: 'originX',
+        axis1: 'x1',
+        axis2: 'x2',
+        dimension: 'width'
+      },
+      { // possible values of origin
+        nearest: 'left',
+        center: 'center',
+        farthest: 'right'
+      }
+    ),
+
+    /**
+     * @private
+     * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line.
+     */
+    _getTopToOriginY: makeEdgeToOriginGetter(
+      { // property names
+        origin: 'originY',
+        axis1: 'y1',
+        axis2: 'y2',
+        dimension: 'height'
+      },
+      { // possible values of origin
+        nearest: 'top',
+        center: 'center',
+        farthest: 'bottom'
+      }
+    ),
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    _render: function(ctx, noTransform) {
+      ctx.beginPath();
+
+      if (noTransform) {
+        //  Line coords are distances from left-top of canvas to origin of line.
+        //  To render line in a path-group, we need to translate them to
+        //  distances from center of path-group to center of line.
+        var cp = this.getCenterPoint();
+        ctx.translate(
+          cp.x - this.strokeWidth / 2,
+          cp.y - this.strokeWidth / 2
+        );
+      }
+
+      if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) {
+        // move from center (of virtual box) to its left/top corner
+        // we can't assume x1, y1 is top left and x2, y2 is bottom right
+        var p = this.calcLinePoints();
+        ctx.moveTo(p.x1, p.y1);
+        ctx.lineTo(p.x2, p.y2);
+      }
+
+      ctx.lineWidth = this.strokeWidth;
+
+      // TODO: test this
+      // make sure setting "fill" changes color of a line
+      // (by copying fillStyle to strokeStyle, since line is stroked, not filled)
+      var origStrokeStyle = ctx.strokeStyle;
+      ctx.strokeStyle = this.stroke || ctx.fillStyle;
+      this.stroke && this._renderStroke(ctx);
+      ctx.strokeStyle = origStrokeStyle;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      var p = this.calcLinePoints();
+
+      ctx.beginPath();
+      fabric.util.drawDashedLine(ctx, p.x1, p.y1, p.x2, p.y2, this.strokeDashArray);
+      ctx.closePath();
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @methd toObject
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints());
+    },
+
+    /**
+     * Recalculates line points given width and height
+     * @private
+     */
+    calcLinePoints: function() {
+      var xMult = this.x1 <= this.x2 ? -1 : 1,
+          yMult = this.y1 <= this.y2 ? -1 : 1,
+          x1 = (xMult * this.width * 0.5),
+          y1 = (yMult * this.height * 0.5),
+          x2 = (xMult * this.width * -0.5),
+          y2 = (yMult * this.height * -0.5);
+
+      return {
+        x1: x1,
+        x2: x2,
+        y1: y1,
+        y2: y2
+      };
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(),
+          p = { x1: this.x1, x2: this.x2, y1: this.y1, y2: this.y2 };
+
+      if (!(this.group && this.group.type === 'path-group')) {
+        p = this.calcLinePoints();
+      }
+      markup.push(
+        '<line ', this.getSvgId(),
+          'x1="', p.x1,
+          '" y1="', p.y1,
+          '" x2="', p.x2,
+          '" y2="', p.y2,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(),
+          this.getSvgTransformMatrix(),
+        '"/>\n'
+      );
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})
+   * @static
+   * @memberOf fabric.Line
+   * @see http://www.w3.org/TR/SVG/shapes.html#LineElement
+   */
+  fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));
+
+  /**
+   * Returns fabric.Line instance from an SVG element
+   * @static
+   * @memberOf fabric.Line
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Line} instance of fabric.Line
+   */
+  fabric.Line.fromElement = function(element, options) {
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES),
+        points = [
+          parsedAttributes.x1 || 0,
+          parsedAttributes.y1 || 0,
+          parsedAttributes.x2 || 0,
+          parsedAttributes.y2 || 0
+        ];
+    return new fabric.Line(points, extend(parsedAttributes, options));
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns fabric.Line instance from an object representation
+   * @static
+   * @memberOf fabric.Line
+   * @param {Object} object Object to create an instance from
+   * @param {function} [callback] invoked with new instance as first argument
+   * @return {fabric.Line} instance of fabric.Line
+   */
+  fabric.Line.fromObject = function(object, callback) {
+    var points = [object.x1, object.y1, object.x2, object.y2],
+        line = new fabric.Line(points, object);
+    callback && callback(line);
+    return line;
+  };
+
+  /**
+   * Produces a function that calculates distance from canvas edge to Line origin.
+   */
+  function makeEdgeToOriginGetter(propertyNames, originValues) {
+    var origin = propertyNames.origin,
+        axis1 = propertyNames.axis1,
+        axis2 = propertyNames.axis2,
+        dimension = propertyNames.dimension,
+        nearest = originValues.nearest,
+        center = originValues.center,
+        farthest = originValues.farthest;
+
+    return function() {
+      switch (this.get(origin)) {
+        case nearest:
+          return Math.min(this.get(axis1), this.get(axis2));
+        case center:
+          return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension));
+        case farthest:
+          return Math.max(this.get(axis1), this.get(axis2));
+      }
+    };
+
+  }
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      pi = Math.PI,
+      extend = fabric.util.object.extend;
+
+  if (fabric.Circle) {
+    fabric.warn('fabric.Circle is already defined.');
+    return;
+  }
+
+  /**
+   * Circle class
+   * @class fabric.Circle
+   * @extends fabric.Object
+   * @see {@link fabric.Circle#initialize} for constructor definition
+   */
+  fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'circle',
+
+    /**
+     * Radius of this circle
+     * @type Number
+     * @default
+     */
+    radius: 0,
+
+    /**
+     * Start angle of the circle, moving clockwise
+     * @type Number
+     * @default 0
+     */
+    startAngle: 0,
+
+    /**
+     * End angle of the circle
+     * @type Number
+     * @default 2Pi
+     */
+    endAngle: pi * 2,
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object
+     * @return {fabric.Circle} thisArg
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.callSuper('initialize', options);
+      this.set('radius', options.radius || 0);
+
+      this.startAngle = options.startAngle || this.startAngle;
+      this.endAngle = options.endAngle || this.endAngle;
+    },
+
+    /**
+     * @private
+     * @param {String} key
+     * @param {*} value
+     * @return {fabric.Circle} thisArg
+     */
+    _set: function(key, value) {
+      this.callSuper('_set', key, value);
+
+      if (key === 'radius') {
+        this.setRadius(value);
+      }
+
+      return this;
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return this.callSuper('toObject', ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude));
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(), x = 0, y = 0,
+          angle = (this.endAngle - this.startAngle) % ( 2 * pi);
+
+      if (angle === 0) {
+        if (this.group && this.group.type === 'path-group') {
+          x = this.left + this.radius;
+          y = this.top + this.radius;
+        }
+        markup.push(
+          '<circle ', this.getSvgId(),
+            'cx="' + x + '" cy="' + y + '" ',
+            'r="', this.radius,
+            '" style="', this.getSvgStyles(),
+            '" transform="', this.getSvgTransform(),
+            ' ', this.getSvgTransformMatrix(),
+          '"/>\n'
+        );
+      }
+      else {
+        var startX = Math.cos(this.startAngle) * this.radius,
+            startY = Math.sin(this.startAngle) * this.radius,
+            endX = Math.cos(this.endAngle) * this.radius,
+            endY = Math.sin(this.endAngle) * this.radius,
+            largeFlag = angle > pi ? '1' : '0';
+
+        markup.push(
+          '<path d="M ' + startX + ' ' + startY,
+          ' A ' + this.radius + ' ' + this.radius,
+          ' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(),
+          ' ', this.getSvgTransformMatrix(),
+          '"/>\n'
+        );
+      }
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx context to render on
+     * @param {Boolean} [noTransform] When true, context is not transformed
+     */
+    _render: function(ctx, noTransform) {
+      ctx.beginPath();
+      ctx.arc(noTransform ? this.left + this.radius : 0,
+              noTransform ? this.top + this.radius : 0,
+              this.radius,
+              this.startAngle,
+              this.endAngle, false);
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * Returns horizontal radius of an object (according to how an object is scaled)
+     * @return {Number}
+     */
+    getRadiusX: function() {
+      return this.get('radius') * this.get('scaleX');
+    },
+
+    /**
+     * Returns vertical radius of an object (according to how an object is scaled)
+     * @return {Number}
+     */
+    getRadiusY: function() {
+      return this.get('radius') * this.get('scaleY');
+    },
+
+    /**
+     * Sets radius of an object (and updates width accordingly)
+     * @return {fabric.Circle} thisArg
+     */
+    setRadius: function(value) {
+      this.radius = value;
+      return this.set('width', value * 2).set('height', value * 2);
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})
+   * @static
+   * @memberOf fabric.Circle
+   * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement
+   */
+  fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));
+
+  /**
+   * Returns {@link fabric.Circle} instance from an SVG element
+   * @static
+   * @memberOf fabric.Circle
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @throws {Error} If value of `r` attribute is missing or invalid
+   * @return {fabric.Circle} Instance of fabric.Circle
+   */
+  fabric.Circle.fromElement = function(element, options) {
+    options || (options = { });
+
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);
+
+    if (!isValidRadius(parsedAttributes)) {
+      throw new Error('value of `r` attribute is required and can not be negative');
+    }
+
+    parsedAttributes.left = parsedAttributes.left || 0;
+    parsedAttributes.top = parsedAttributes.top || 0;
+
+    var obj = new fabric.Circle(extend(parsedAttributes, options));
+
+    obj.left -= obj.radius;
+    obj.top -= obj.radius;
+    return obj;
+  };
+
+  /**
+   * @private
+   */
+  function isValidRadius(attributes) {
+    return (('radius' in attributes) && (attributes.radius >= 0));
+  }
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns {@link fabric.Circle} instance from an object representation
+   * @static
+   * @memberOf fabric.Circle
+   * @param {Object} object Object to create an instance from
+   * @param {function} [callback] invoked with new instance as first argument
+   * @return {Object} Instance of fabric.Circle
+   */
+  fabric.Circle.fromObject = function(object, callback) {
+    var circle = new fabric.Circle(object);
+    callback && callback(circle);
+    return circle;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { });
+
+  if (fabric.Triangle) {
+    fabric.warn('fabric.Triangle is already defined');
+    return;
+  }
+
+  /**
+   * Triangle class
+   * @class fabric.Triangle
+   * @extends fabric.Object
+   * @return {fabric.Triangle} thisArg
+   * @see {@link fabric.Triangle#initialize} for constructor definition
+   */
+  fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'triangle',
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object
+     * @return {Object} thisArg
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.callSuper('initialize', options);
+
+      this.set('width', options.width || 100)
+          .set('height', options.height || 100);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _render: function(ctx) {
+      var widthBy2 = this.width / 2,
+          heightBy2 = this.height / 2;
+
+      ctx.beginPath();
+      ctx.moveTo(-widthBy2, heightBy2);
+      ctx.lineTo(0, -heightBy2);
+      ctx.lineTo(widthBy2, heightBy2);
+      ctx.closePath();
+
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      var widthBy2 = this.width / 2,
+          heightBy2 = this.height / 2;
+
+      ctx.beginPath();
+      fabric.util.drawDashedLine(ctx, -widthBy2, heightBy2, 0, -heightBy2, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, 0, -heightBy2, widthBy2, heightBy2, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, widthBy2, heightBy2, -widthBy2, heightBy2, this.strokeDashArray);
+      ctx.closePath();
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(),
+          widthBy2 = this.width / 2,
+          heightBy2 = this.height / 2,
+          points = [
+            -widthBy2 + ' ' + heightBy2,
+            '0 ' + -heightBy2,
+            widthBy2 + ' ' + heightBy2
+          ]
+          .join(',');
+
+      markup.push(
+        '<polygon ', this.getSvgId(),
+          'points="', points,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(),
+        '"/>'
+      );
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /**
+   * Returns fabric.Triangle instance from an object representation
+   * @static
+   * @memberOf fabric.Triangle
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Triangle instance is created
+   * @return {Object} instance of Canvas.Triangle
+   */
+  fabric.Triangle.fromObject = function(object, callback) {
+    var triangle = new fabric.Triangle(object);
+    callback && callback(triangle);
+    return triangle;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      piBy2   = Math.PI * 2,
+      extend = fabric.util.object.extend;
+
+  if (fabric.Ellipse) {
+    fabric.warn('fabric.Ellipse is already defined.');
+    return;
+  }
+
+  /**
+   * Ellipse class
+   * @class fabric.Ellipse
+   * @extends fabric.Object
+   * @return {fabric.Ellipse} thisArg
+   * @see {@link fabric.Ellipse#initialize} for constructor definition
+   */
+  fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'ellipse',
+
+    /**
+     * Horizontal radius
+     * @type Number
+     * @default
+     */
+    rx:   0,
+
+    /**
+     * Vertical radius
+     * @type Number
+     * @default
+     */
+    ry:   0,
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object
+     * @return {fabric.Ellipse} thisArg
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.callSuper('initialize', options);
+
+      this.set('rx', options.rx || 0);
+      this.set('ry', options.ry || 0);
+    },
+
+    /**
+     * @private
+     * @param {String} key
+     * @param {*} value
+     * @return {fabric.Ellipse} thisArg
+     */
+    _set: function(key, value) {
+      this.callSuper('_set', key, value);
+      switch (key) {
+
+        case 'rx':
+          this.rx = value;
+          this.set('width', value * 2);
+          break;
+
+        case 'ry':
+          this.ry = value;
+          this.set('height', value * 2);
+          break;
+
+      }
+      return this;
+    },
+
+    /**
+     * Returns horizontal radius of an object (according to how an object is scaled)
+     * @return {Number}
+     */
+    getRx: function() {
+      return this.get('rx') * this.get('scaleX');
+    },
+
+    /**
+     * Returns Vertical radius of an object (according to how an object is scaled)
+     * @return {Number}
+     */
+    getRy: function() {
+      return this.get('ry') * this.get('scaleY');
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(), x = 0, y = 0;
+      if (this.group && this.group.type === 'path-group') {
+        x = this.left + this.rx;
+        y = this.top + this.ry;
+      }
+      markup.push(
+        '<ellipse ', this.getSvgId(),
+          'cx="', x, '" cy="', y, '" ',
+          'rx="', this.rx,
+          '" ry="', this.ry,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(),
+          this.getSvgTransformMatrix(),
+        '"/>\n'
+      );
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx context to render on
+     * @param {Boolean} [noTransform] When true, context is not transformed
+     */
+    _render: function(ctx, noTransform) {
+      ctx.beginPath();
+      ctx.save();
+      ctx.transform(1, 0, 0, this.ry / this.rx, 0, 0);
+      ctx.arc(
+        noTransform ? this.left + this.rx : 0,
+        noTransform ? (this.top + this.ry) * this.rx / this.ry : 0,
+        this.rx,
+        0,
+        piBy2,
+        false);
+      ctx.restore();
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})
+   * @static
+   * @memberOf fabric.Ellipse
+   * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement
+   */
+  fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' '));
+
+  /**
+   * Returns {@link fabric.Ellipse} instance from an SVG element
+   * @static
+   * @memberOf fabric.Ellipse
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Ellipse}
+   */
+  fabric.Ellipse.fromElement = function(element, options) {
+    options || (options = { });
+
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
+
+    parsedAttributes.left = parsedAttributes.left || 0;
+    parsedAttributes.top = parsedAttributes.top || 0;
+
+    var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));
+
+    ellipse.top -= ellipse.ry;
+    ellipse.left -= ellipse.rx;
+    return ellipse;
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns {@link fabric.Ellipse} instance from an object representation
+   * @static
+   * @memberOf fabric.Ellipse
+   * @param {Object} object Object to create an instance from
+   * @param {function} [callback] invoked with new instance as first argument
+   * @return {fabric.Ellipse}
+   */
+  fabric.Ellipse.fromObject = function(object, callback) {
+    var ellipse = new fabric.Ellipse(object);
+    callback && callback(ellipse);
+    return ellipse;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend;
+
+  if (fabric.Rect) {
+    fabric.warn('fabric.Rect is already defined');
+    return;
+  }
+
+  var stateProperties = fabric.Object.prototype.stateProperties.concat();
+  stateProperties.push('rx', 'ry', 'x', 'y');
+
+  /**
+   * Rectangle class
+   * @class fabric.Rect
+   * @extends fabric.Object
+   * @return {fabric.Rect} thisArg
+   * @see {@link fabric.Rect#initialize} for constructor definition
+   */
+  fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {
+
+    /**
+     * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})
+     * as well as for history (undo/redo) purposes
+     * @type Array
+     */
+    stateProperties: stateProperties,
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'rect',
+
+    /**
+     * Horizontal border radius
+     * @type Number
+     * @default
+     */
+    rx:   0,
+
+    /**
+     * Vertical border radius
+     * @type Number
+     * @default
+     */
+    ry:   0,
+
+    /**
+     * Used to specify dash pattern for stroke on this object
+     * @type Array
+     */
+    strokeDashArray: null,
+
+    /**
+     * Constructor
+     * @param {Object} [options] Options object
+     * @return {Object} thisArg
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.callSuper('initialize', options);
+      this._initRxRy();
+
+    },
+
+    /**
+     * Initializes rx/ry attributes
+     * @private
+     */
+    _initRxRy: function() {
+      if (this.rx && !this.ry) {
+        this.ry = this.rx;
+      }
+      else if (this.ry && !this.rx) {
+        this.rx = this.ry;
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    _render: function(ctx, noTransform) {
+
+      // optimize 1x1 case (used in spray brush)
+      if (this.width === 1 && this.height === 1) {
+        ctx.fillRect(-0.5, -0.5, 1, 1);
+        return;
+      }
+
+      var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,
+          ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,
+          w = this.width,
+          h = this.height,
+          x = noTransform ? this.left : -this.width / 2,
+          y = noTransform ? this.top : -this.height / 2,
+          isRounded = rx !== 0 || ry !== 0,
+          /* "magic number" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */
+          k = 1 - 0.5522847498;
+      ctx.beginPath();
+
+      ctx.moveTo(x + rx, y);
+
+      ctx.lineTo(x + w - rx, y);
+      isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);
+
+      ctx.lineTo(x + w, y + h - ry);
+      isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h);
+
+      ctx.lineTo(x + rx, y + h);
+      isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);
+
+      ctx.lineTo(x, y + ry);
+      isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);
+
+      ctx.closePath();
+
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      var x = -this.width / 2,
+          y = -this.height / 2,
+          w = this.width,
+          h = this.height;
+
+      ctx.beginPath();
+      fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);
+      ctx.closePath();
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(), x = this.left, y = this.top;
+      if (!(this.group && this.group.type === 'path-group')) {
+        x = -this.width / 2;
+        y = -this.height / 2;
+      }
+      markup.push(
+        '<rect ', this.getSvgId(),
+          'x="', x, '" y="', y,
+          '" rx="', this.get('rx'), '" ry="', this.get('ry'),
+          '" width="', this.width, '" height="', this.height,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(),
+          this.getSvgTransformMatrix(),
+        '"/>\n');
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)
+   * @static
+   * @memberOf fabric.Rect
+   * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement
+   */
+  fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));
+
+  /**
+   * Returns {@link fabric.Rect} instance from an SVG element
+   * @static
+   * @memberOf fabric.Rect
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Rect} Instance of fabric.Rect
+   */
+  fabric.Rect.fromElement = function(element, options) {
+    if (!element) {
+      return null;
+    }
+    options = options || { };
+
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);
+
+    parsedAttributes.left = parsedAttributes.left || 0;
+    parsedAttributes.top  = parsedAttributes.top  || 0;
+    var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
+    rect.visible = rect.visible && rect.width > 0 && rect.height > 0;
+    return rect;
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns {@link fabric.Rect} instance from an object representation
+   * @static
+   * @memberOf fabric.Rect
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created
+   * @return {Object} instance of fabric.Rect
+   */
+  fabric.Rect.fromObject = function(object, callback) {
+    var rect = new fabric.Rect(object);
+    callback && callback(rect);
+    return rect;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { });
+
+  if (fabric.Polyline) {
+    fabric.warn('fabric.Polyline is already defined');
+    return;
+  }
+
+  /**
+   * Polyline class
+   * @class fabric.Polyline
+   * @extends fabric.Object
+   * @see {@link fabric.Polyline#initialize} for constructor definition
+   */
+  fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'polyline',
+
+    /**
+     * Points array
+     * @type Array
+     * @default
+     */
+    points: null,
+
+    /**
+     * Minimum X from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minX: 0,
+
+    /**
+     * Minimum Y from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minY: 0,
+
+    /**
+     * Constructor
+     * @param {Array} points Array of points (where each point is an object with x and y)
+     * @param {Object} [options] Options object
+     * @return {fabric.Polyline} thisArg
+     * @example
+     * var poly = new fabric.Polyline([
+     *     { x: 10, y: 10 },
+     *     { x: 50, y: 30 },
+     *     { x: 40, y: 70 },
+     *     { x: 60, y: 50 },
+     *     { x: 100, y: 150 },
+     *     { x: 40, y: 100 }
+     *   ], {
+     *   stroke: 'red',
+     *   left: 100,
+     *   top: 100
+     * });
+     */
+    initialize: function(points, options) {
+      return fabric.Polygon.prototype.initialize.call(this, points, options);
+    },
+
+    /**
+     * @private
+     */
+    _calcDimensions: function() {
+      return fabric.Polygon.prototype._calcDimensions.call(this);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return fabric.Polygon.prototype.toObject.call(this, propertiesToInclude);
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      return fabric.Polygon.prototype.toSVG.call(this, reviver);
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    _render: function(ctx, noTransform) {
+      if (!fabric.Polygon.prototype.commonRender.call(this, ctx, noTransform)) {
+        return;
+      }
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      var p1, p2;
+
+      ctx.beginPath();
+      for (var i = 0, len = this.points.length; i < len; i++) {
+        p1 = this.points[i];
+        p2 = this.points[i + 1] || p1;
+        fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);
+      }
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return this.get('points').length;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement})
+   * @static
+   * @memberOf fabric.Polyline
+   * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement
+   */
+  fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();
+
+  /**
+   * Returns fabric.Polyline instance from an SVG element
+   * @static
+   * @memberOf fabric.Polyline
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Polyline} Instance of fabric.Polyline
+   */
+  fabric.Polyline.fromElement = function(element, options) {
+    if (!element) {
+      return null;
+    }
+    options || (options = { });
+
+    var points = fabric.parsePointsAttribute(element.getAttribute('points')),
+        parsedAttributes = fabric.parseAttributes(element, fabric.Polyline.ATTRIBUTE_NAMES);
+
+    return new fabric.Polyline(points, fabric.util.object.extend(parsedAttributes, options));
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns fabric.Polyline instance from an object representation
+   * @static
+   * @memberOf fabric.Polyline
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created
+   * @return {fabric.Polyline} Instance of fabric.Polyline
+   */
+  fabric.Polyline.fromObject = function(object, callback) {
+    var polyline = new fabric.Polyline(object.points, object);
+    callback && callback(polyline);
+    return polyline;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      min = fabric.util.array.min,
+      max = fabric.util.array.max,
+      toFixed = fabric.util.toFixed;
+
+  if (fabric.Polygon) {
+    fabric.warn('fabric.Polygon is already defined');
+    return;
+  }
+
+  /**
+   * Polygon class
+   * @class fabric.Polygon
+   * @extends fabric.Object
+   * @see {@link fabric.Polygon#initialize} for constructor definition
+   */
+  fabric.Polygon = fabric.util.createClass(fabric.Object, /** @lends fabric.Polygon.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'polygon',
+
+    /**
+     * Points array
+     * @type Array
+     * @default
+     */
+    points: null,
+
+    /**
+     * Minimum X from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minX: 0,
+
+    /**
+     * Minimum Y from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minY: 0,
+
+    /**
+     * Constructor
+     * @param {Array} points Array of points
+     * @param {Object} [options] Options object
+     * @return {fabric.Polygon} thisArg
+     */
+    initialize: function(points, options) {
+      options = options || { };
+      this.points = points || [];
+      this.callSuper('initialize', options);
+      this._calcDimensions();
+      if (!('top' in options)) {
+        this.top = this.minY;
+      }
+      if (!('left' in options)) {
+        this.left = this.minX;
+      }
+      this.pathOffset = {
+        x: this.minX + this.width / 2,
+        y: this.minY + this.height / 2
+      };
+    },
+
+    /**
+     * @private
+     */
+    _calcDimensions: function() {
+
+      var points = this.points,
+          minX = min(points, 'x'),
+          minY = min(points, 'y'),
+          maxX = max(points, 'x'),
+          maxY = max(points, 'y');
+
+      this.width = (maxX - minX) || 0;
+      this.height = (maxY - minY) || 0;
+      this.minX = minX || 0;
+      this.minY = minY || 0;
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return extend(this.callSuper('toObject', propertiesToInclude), {
+        points: this.points.concat()
+      });
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var points = [], addTransform,
+          markup = this._createBaseSVGMarkup();
+
+      for (var i = 0, len = this.points.length; i < len; i++) {
+        points.push(toFixed(this.points[i].x, 2), ',', toFixed(this.points[i].y, 2), ' ');
+      }
+      if (!(this.group && this.group.type === 'path-group')) {
+        addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') ';
+      }
+      markup.push(
+        '<', this.type, ' ', this.getSvgId(),
+          'points="', points.join(''),
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(), addTransform,
+          ' ', this.getSvgTransformMatrix(),
+        '"/>\n'
+      );
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    _render: function(ctx, noTransform) {
+      if (!this.commonRender(ctx, noTransform)) {
+        return;
+      }
+      this._renderFill(ctx);
+      if (this.stroke || this.strokeDashArray) {
+        ctx.closePath();
+        this._renderStroke(ctx);
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    commonRender: function(ctx, noTransform) {
+      var point, len = this.points.length;
+
+      if (!len || isNaN(this.points[len - 1].y)) {
+        // do not draw if no points or odd points
+        // NaN comes from parseFloat of a empty string in parser
+        return false;
+      }
+
+      noTransform || ctx.translate(-this.pathOffset.x, -this.pathOffset.y);
+      ctx.beginPath();
+      ctx.moveTo(this.points[0].x, this.points[0].y);
+      for (var i = 0; i < len; i++) {
+        point = this.points[i];
+        ctx.lineTo(point.x, point.y);
+      }
+      return true;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      fabric.Polyline.prototype._renderDashedStroke.call(this, ctx);
+      ctx.closePath();
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return this.points.length;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)
+   * @static
+   * @memberOf fabric.Polygon
+   * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement
+   */
+  fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();
+
+  /**
+   * Returns {@link fabric.Polygon} instance from an SVG element
+   * @static
+   * @memberOf fabric.Polygon
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Polygon} Instance of fabric.Polygon
+   */
+  fabric.Polygon.fromElement = function(element, options) {
+    if (!element) {
+      return null;
+    }
+
+    options || (options = { });
+
+    var points = fabric.parsePointsAttribute(element.getAttribute('points')),
+        parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES);
+
+    return new fabric.Polygon(points, extend(parsedAttributes, options));
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns fabric.Polygon instance from an object representation
+   * @static
+   * @memberOf fabric.Polygon
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created
+   * @return {fabric.Polygon} Instance of fabric.Polygon
+   */
+  fabric.Polygon.fromObject = function(object, callback) {
+    var polygon = new fabric.Polygon(object.points, object);
+    callback && callback(polygon);
+    return polygon;
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      min = fabric.util.array.min,
+      max = fabric.util.array.max,
+      extend = fabric.util.object.extend,
+      _toString = Object.prototype.toString,
+      drawArc = fabric.util.drawArc,
+      commandLengths = {
+        m: 2,
+        l: 2,
+        h: 1,
+        v: 1,
+        c: 6,
+        s: 4,
+        q: 4,
+        t: 2,
+        a: 7
+      },
+      repeatedCommands = {
+        m: 'l',
+        M: 'L'
+      };
+
+  if (fabric.Path) {
+    fabric.warn('fabric.Path is already defined');
+    return;
+  }
+
+  /**
+   * Path class
+   * @class fabric.Path
+   * @extends fabric.Object
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}
+   * @see {@link fabric.Path#initialize} for constructor definition
+   */
+  fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'path',
+
+    /**
+     * Array of path points
+     * @type Array
+     * @default
+     */
+    path: null,
+
+    /**
+     * Minimum X from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minX: 0,
+
+    /**
+     * Minimum Y from points values, necessary to offset points
+     * @type Number
+     * @default
+     */
+    minY: 0,
+
+    /**
+     * Constructor
+     * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
+     * @param {Object} [options] Options object
+     * @return {fabric.Path} thisArg
+     */
+    initialize: function(path, options) {
+      options = options || { };
+
+      this.setOptions(options);
+
+      if (!path) {
+        path = [];
+      }
+
+      var fromArray = _toString.call(path) === '[object Array]';
+
+      this.path = fromArray
+        ? path
+        // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)
+        : path.match && path.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);
+
+      if (!this.path) {
+        return;
+      }
+
+      if (!fromArray) {
+        this.path = this._parsePath();
+      }
+
+      this._setPositionDimensions(options);
+
+      if (options.sourcePath) {
+        this.setSourcePath(options.sourcePath);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} options Options object
+     */
+    _setPositionDimensions: function(options) {
+      var calcDim = this._parseDimensions();
+
+      this.minX = calcDim.left;
+      this.minY = calcDim.top;
+      this.width = calcDim.width;
+      this.height = calcDim.height;
+
+      if (typeof options.left === 'undefined') {
+        this.left = calcDim.left + (this.originX === 'center'
+          ? this.width / 2
+          : this.originX === 'right'
+            ? this.width
+            : 0);
+      }
+
+      if (typeof options.top === 'undefined') {
+        this.top = calcDim.top + (this.originY === 'center'
+          ? this.height / 2
+          : this.originY === 'bottom'
+            ? this.height
+            : 0);
+      }
+
+      this.pathOffset = this.pathOffset || {
+        x: this.minX + this.width / 2,
+        y: this.minY + this.height / 2
+      };
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx context to render path on
+     */
+    _renderPathCommands: function(ctx) {
+      var current, // current instruction
+          previous = null,
+          subpathStartX = 0,
+          subpathStartY = 0,
+          x = 0, // current x
+          y = 0, // current y
+          controlX = 0, // current control point x
+          controlY = 0, // current control point y
+          tempX,
+          tempY,
+          l = -this.pathOffset.x,
+          t = -this.pathOffset.y;
+
+      if (this.group && this.group.type === 'path-group') {
+        l = 0;
+        t = 0;
+      }
+
+      ctx.beginPath();
+
+      for (var i = 0, len = this.path.length; i < len; ++i) {
+
+        current = this.path[i];
+
+        switch (current[0]) { // first letter
+
+          case 'l': // lineto, relative
+            x += current[1];
+            y += current[2];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'L': // lineto, absolute
+            x = current[1];
+            y = current[2];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'h': // horizontal lineto, relative
+            x += current[1];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'H': // horizontal lineto, absolute
+            x = current[1];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'v': // vertical lineto, relative
+            y += current[1];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'V': // verical lineto, absolute
+            y = current[1];
+            ctx.lineTo(x + l, y + t);
+            break;
+
+          case 'm': // moveTo, relative
+            x += current[1];
+            y += current[2];
+            subpathStartX = x;
+            subpathStartY = y;
+            ctx.moveTo(x + l, y + t);
+            break;
+
+          case 'M': // moveTo, absolute
+            x = current[1];
+            y = current[2];
+            subpathStartX = x;
+            subpathStartY = y;
+            ctx.moveTo(x + l, y + t);
+            break;
+
+          case 'c': // bezierCurveTo, relative
+            tempX = x + current[5];
+            tempY = y + current[6];
+            controlX = x + current[3];
+            controlY = y + current[4];
+            ctx.bezierCurveTo(
+              x + current[1] + l, // x1
+              y + current[2] + t, // y1
+              controlX + l, // x2
+              controlY + t, // y2
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'C': // bezierCurveTo, absolute
+            x = current[5];
+            y = current[6];
+            controlX = current[3];
+            controlY = current[4];
+            ctx.bezierCurveTo(
+              current[1] + l,
+              current[2] + t,
+              controlX + l,
+              controlY + t,
+              x + l,
+              y + t
+            );
+            break;
+
+          case 's': // shorthand cubic bezierCurveTo, relative
+
+            // transform to absolute x,y
+            tempX = x + current[3];
+            tempY = y + current[4];
+
+            if (previous[0].match(/[CcSs]/) === null) {
+              // If there is no previous command or if the previous command was not a C, c, S, or s,
+              // the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control points
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+
+            ctx.bezierCurveTo(
+              controlX + l,
+              controlY + t,
+              x + current[1] + l,
+              y + current[2] + t,
+              tempX + l,
+              tempY + t
+            );
+            // set control point to 2nd one of this command
+            // "... the first control point is assumed to be
+            // the reflection of the second control point on
+            // the previous command relative to the current point."
+            controlX = x + current[1];
+            controlY = y + current[2];
+
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'S': // shorthand cubic bezierCurveTo, absolute
+            tempX = current[3];
+            tempY = current[4];
+            if (previous[0].match(/[CcSs]/) === null) {
+              // If there is no previous command or if the previous command was not a C, c, S, or s,
+              // the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control points
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+            ctx.bezierCurveTo(
+              controlX + l,
+              controlY + t,
+              current[1] + l,
+              current[2] + t,
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+
+            // set control point to 2nd one of this command
+            // "... the first control point is assumed to be
+            // the reflection of the second control point on
+            // the previous command relative to the current point."
+            controlX = current[1];
+            controlY = current[2];
+
+            break;
+
+          case 'q': // quadraticCurveTo, relative
+            // transform to absolute x,y
+            tempX = x + current[3];
+            tempY = y + current[4];
+
+            controlX = x + current[1];
+            controlY = y + current[2];
+
+            ctx.quadraticCurveTo(
+              controlX + l,
+              controlY + t,
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'Q': // quadraticCurveTo, absolute
+            tempX = current[3];
+            tempY = current[4];
+
+            ctx.quadraticCurveTo(
+              current[1] + l,
+              current[2] + t,
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+            controlX = current[1];
+            controlY = current[2];
+            break;
+
+          case 't': // shorthand quadraticCurveTo, relative
+
+            // transform to absolute x,y
+            tempX = x + current[1];
+            tempY = y + current[2];
+
+            if (previous[0].match(/[QqTt]/) === null) {
+              // If there is no previous command or if the previous command was not a Q, q, T or t,
+              // assume the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control point
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+
+            ctx.quadraticCurveTo(
+              controlX + l,
+              controlY + t,
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+
+            break;
+
+          case 'T':
+            tempX = current[1];
+            tempY = current[2];
+
+            if (previous[0].match(/[QqTt]/) === null) {
+              // If there is no previous command or if the previous command was not a Q, q, T or t,
+              // assume the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control point
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+            ctx.quadraticCurveTo(
+              controlX + l,
+              controlY + t,
+              tempX + l,
+              tempY + t
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'a':
+            // TODO: optimize this
+            drawArc(ctx, x + l, y + t, [
+              current[1],
+              current[2],
+              current[3],
+              current[4],
+              current[5],
+              current[6] + x + l,
+              current[7] + y + t
+            ]);
+            x += current[6];
+            y += current[7];
+            break;
+
+          case 'A':
+            // TODO: optimize this
+            drawArc(ctx, x + l, y + t, [
+              current[1],
+              current[2],
+              current[3],
+              current[4],
+              current[5],
+              current[6] + l,
+              current[7] + t
+            ]);
+            x = current[6];
+            y = current[7];
+            break;
+
+          case 'z':
+          case 'Z':
+            x = subpathStartX;
+            y = subpathStartY;
+            ctx.closePath();
+            break;
+        }
+        previous = current;
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx context to render path on
+     */
+    _render: function(ctx) {
+      this._renderPathCommands(ctx);
+      this._renderFill(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * Returns string representation of an instance
+     * @return {String} string representation of an instance
+     */
+    toString: function() {
+      return '#<fabric.Path (' + this.complexity() +
+        '): { "top": ' + this.top + ', "left": ' + this.left + ' }>';
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      var o = extend(this.callSuper('toObject', ['sourcePath', 'pathOffset'].concat(propertiesToInclude)), {
+        path: this.path.map(function(item) { return item.slice() })
+      });
+      return o;
+    },
+
+    /**
+     * Returns dataless object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toDatalessObject: function(propertiesToInclude) {
+      var o = this.toObject(propertiesToInclude);
+      if (this.sourcePath) {
+        o.path = this.sourcePath;
+      }
+      delete o.sourcePath;
+      return o;
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var chunks = [],
+          markup = this._createBaseSVGMarkup(), addTransform = '';
+
+      for (var i = 0, len = this.path.length; i < len; i++) {
+        chunks.push(this.path[i].join(' '));
+      }
+      var path = chunks.join(' ');
+      if (!(this.group && this.group.type === 'path-group')) {
+        addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') ';
+      }
+      markup.push(
+        '<path ', this.getSvgId(),
+          'd="', path,
+          '" style="', this.getSvgStyles(),
+          '" transform="', this.getSvgTransform(), addTransform,
+          this.getSvgTransformMatrix(), '" stroke-linecap="round" ',
+        '/>\n'
+      );
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns number representation of an instance complexity
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return this.path.length;
+    },
+
+    /**
+     * @private
+     */
+    _parsePath: function() {
+      var result = [],
+          coords = [],
+          currentPath,
+          parsed,
+          re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig,
+          match,
+          coordsStr;
+
+      for (var i = 0, coordsParsed, len = this.path.length; i < len; i++) {
+        currentPath = this.path[i];
+
+        coordsStr = currentPath.slice(1).trim();
+        coords.length = 0;
+
+        while ((match = re.exec(coordsStr))) {
+          coords.push(match[0]);
+        }
+
+        coordsParsed = [currentPath.charAt(0)];
+
+        for (var j = 0, jlen = coords.length; j < jlen; j++) {
+          parsed = parseFloat(coords[j]);
+          if (!isNaN(parsed)) {
+            coordsParsed.push(parsed);
+          }
+        }
+
+        var command = coordsParsed[0],
+            commandLength = commandLengths[command.toLowerCase()],
+            repeatedCommand = repeatedCommands[command] || command;
+
+        if (coordsParsed.length - 1 > commandLength) {
+          for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) {
+            result.push([command].concat(coordsParsed.slice(k, k + commandLength)));
+            command = repeatedCommand;
+          }
+        }
+        else {
+          result.push(coordsParsed);
+        }
+      }
+
+      return result;
+    },
+
+    /**
+     * @private
+     */
+    _parseDimensions: function() {
+
+      var aX = [],
+          aY = [],
+          current, // current instruction
+          previous = null,
+          subpathStartX = 0,
+          subpathStartY = 0,
+          x = 0, // current x
+          y = 0, // current y
+          controlX = 0, // current control point x
+          controlY = 0, // current control point y
+          tempX,
+          tempY,
+          bounds;
+
+      for (var i = 0, len = this.path.length; i < len; ++i) {
+
+        current = this.path[i];
+
+        switch (current[0]) { // first letter
+
+          case 'l': // lineto, relative
+            x += current[1];
+            y += current[2];
+            bounds = [];
+            break;
+
+          case 'L': // lineto, absolute
+            x = current[1];
+            y = current[2];
+            bounds = [];
+            break;
+
+          case 'h': // horizontal lineto, relative
+            x += current[1];
+            bounds = [];
+            break;
+
+          case 'H': // horizontal lineto, absolute
+            x = current[1];
+            bounds = [];
+            break;
+
+          case 'v': // vertical lineto, relative
+            y += current[1];
+            bounds = [];
+            break;
+
+          case 'V': // verical lineto, absolute
+            y = current[1];
+            bounds = [];
+            break;
+
+          case 'm': // moveTo, relative
+            x += current[1];
+            y += current[2];
+            subpathStartX = x;
+            subpathStartY = y;
+            bounds = [];
+            break;
+
+          case 'M': // moveTo, absolute
+            x = current[1];
+            y = current[2];
+            subpathStartX = x;
+            subpathStartY = y;
+            bounds = [];
+            break;
+
+          case 'c': // bezierCurveTo, relative
+            tempX = x + current[5];
+            tempY = y + current[6];
+            controlX = x + current[3];
+            controlY = y + current[4];
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              x + current[1], // x1
+              y + current[2], // y1
+              controlX, // x2
+              controlY, // y2
+              tempX,
+              tempY
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'C': // bezierCurveTo, absolute
+            x = current[5];
+            y = current[6];
+            controlX = current[3];
+            controlY = current[4];
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              current[1],
+              current[2],
+              controlX,
+              controlY,
+              x,
+              y
+            );
+            break;
+
+          case 's': // shorthand cubic bezierCurveTo, relative
+
+            // transform to absolute x,y
+            tempX = x + current[3];
+            tempY = y + current[4];
+
+            if (previous[0].match(/[CcSs]/) === null) {
+              // If there is no previous command or if the previous command was not a C, c, S, or s,
+              // the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control points
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              x + current[1],
+              y + current[2],
+              tempX,
+              tempY
+            );
+            // set control point to 2nd one of this command
+            // "... the first control point is assumed to be
+            // the reflection of the second control point on
+            // the previous command relative to the current point."
+            controlX = x + current[1];
+            controlY = y + current[2];
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'S': // shorthand cubic bezierCurveTo, absolute
+            tempX = current[3];
+            tempY = current[4];
+            if (previous[0].match(/[CcSs]/) === null) {
+              // If there is no previous command or if the previous command was not a C, c, S, or s,
+              // the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control points
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              current[1],
+              current[2],
+              tempX,
+              tempY
+            );
+            x = tempX;
+            y = tempY;
+            // set control point to 2nd one of this command
+            // "... the first control point is assumed to be
+            // the reflection of the second control point on
+            // the previous command relative to the current point."
+            controlX = current[1];
+            controlY = current[2];
+            break;
+
+          case 'q': // quadraticCurveTo, relative
+            // transform to absolute x,y
+            tempX = x + current[3];
+            tempY = y + current[4];
+            controlX = x + current[1];
+            controlY = y + current[2];
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              controlX,
+              controlY,
+              tempX,
+              tempY
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'Q': // quadraticCurveTo, absolute
+            controlX = current[1];
+            controlY = current[2];
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              controlX,
+              controlY,
+              current[3],
+              current[4]
+            );
+            x = current[3];
+            y = current[4];
+            break;
+
+          case 't': // shorthand quadraticCurveTo, relative
+            // transform to absolute x,y
+            tempX = x + current[1];
+            tempY = y + current[2];
+            if (previous[0].match(/[QqTt]/) === null) {
+              // If there is no previous command or if the previous command was not a Q, q, T or t,
+              // assume the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control point
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              controlX,
+              controlY,
+              tempX,
+              tempY
+            );
+            x = tempX;
+            y = tempY;
+
+            break;
+
+          case 'T':
+            tempX = current[1];
+            tempY = current[2];
+
+            if (previous[0].match(/[QqTt]/) === null) {
+              // If there is no previous command or if the previous command was not a Q, q, T or t,
+              // assume the control point is coincident with the current point
+              controlX = x;
+              controlY = y;
+            }
+            else {
+              // calculate reflection of previous control point
+              controlX = 2 * x - controlX;
+              controlY = 2 * y - controlY;
+            }
+            bounds = fabric.util.getBoundsOfCurve(x, y,
+              controlX,
+              controlY,
+              controlX,
+              controlY,
+              tempX,
+              tempY
+            );
+            x = tempX;
+            y = tempY;
+            break;
+
+          case 'a':
+            // TODO: optimize this
+            bounds = fabric.util.getBoundsOfArc(x, y,
+              current[1],
+              current[2],
+              current[3],
+              current[4],
+              current[5],
+              current[6] + x,
+              current[7] + y
+            );
+            x += current[6];
+            y += current[7];
+            break;
+
+          case 'A':
+            // TODO: optimize this
+            bounds = fabric.util.getBoundsOfArc(x, y,
+              current[1],
+              current[2],
+              current[3],
+              current[4],
+              current[5],
+              current[6],
+              current[7]
+            );
+            x = current[6];
+            y = current[7];
+            break;
+
+          case 'z':
+          case 'Z':
+            x = subpathStartX;
+            y = subpathStartY;
+            break;
+        }
+        previous = current;
+        bounds.forEach(function (point) {
+          aX.push(point.x);
+          aY.push(point.y);
+        });
+        aX.push(x);
+        aY.push(y);
+      }
+
+      var minX = min(aX) || 0,
+          minY = min(aY) || 0,
+          maxX = max(aX) || 0,
+          maxY = max(aY) || 0,
+          deltaX = maxX - minX,
+          deltaY = maxY - minY,
+
+          o = {
+            left: minX,
+            top: minY,
+            width: deltaX,
+            height: deltaY
+          };
+
+      return o;
+    }
+  });
+
+  /**
+   * Creates an instance of fabric.Path from an object
+   * @static
+   * @memberOf fabric.Path
+   * @param {Object} object
+   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created
+   */
+  fabric.Path.fromObject = function(object, callback) {
+    // remove this pattern rom 2.0, accept just object.
+    var path;
+    if (typeof object.path === 'string') {
+      fabric.loadSVGFromURL(object.path, function (elements) {
+        var pathUrl = object.path;
+        path = elements[0];
+        delete object.path;
+
+        fabric.util.object.extend(path, object);
+        path.setSourcePath(pathUrl);
+
+        callback && callback(path);
+      });
+    }
+    else {
+      path = new fabric.Path(object.path, object);
+      callback && callback(path);
+      return path;
+    }
+  };
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`)
+   * @static
+   * @memberOf fabric.Path
+   * @see http://www.w3.org/TR/SVG/paths.html#PathElement
+   */
+  fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']);
+
+  /**
+   * Creates an instance of fabric.Path from an SVG <path> element
+   * @static
+   * @memberOf fabric.Path
+   * @param {SVGElement} element to parse
+   * @param {Function} callback Callback to invoke when an fabric.Path instance is created
+   * @param {Object} [options] Options object
+   */
+  fabric.Path.fromElement = function(element, callback, options) {
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);
+    callback && callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)));
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Indicates that instances of this type are async
+   * @static
+   * @memberOf fabric.Path
+   * @type Boolean
+   * @default
+   */
+  fabric.Path.async = true;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      invoke = fabric.util.array.invoke,
+      parentToObject = fabric.Object.prototype.toObject;
+
+  if (fabric.PathGroup) {
+    fabric.warn('fabric.PathGroup is already defined');
+    return;
+  }
+
+  /**
+   * Path group class
+   * @class fabric.PathGroup
+   * @extends fabric.Path
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}
+   * @see {@link fabric.PathGroup#initialize} for constructor definition
+   */
+  fabric.PathGroup = fabric.util.createClass(fabric.Path, /** @lends fabric.PathGroup.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'path-group',
+
+    /**
+     * Fill value
+     * @type String
+     * @default
+     */
+    fill: '',
+
+    /**
+     * Constructor
+     * @param {Array} paths
+     * @param {Object} [options] Options object
+     * @return {fabric.PathGroup} thisArg
+     */
+    initialize: function(paths, options) {
+
+      options = options || { };
+      this.paths = paths || [];
+
+      for (var i = this.paths.length; i--;) {
+        this.paths[i].group = this;
+      }
+
+      if (options.toBeParsed) {
+        this.parseDimensionsFromPaths(options);
+        delete options.toBeParsed;
+      }
+      this.setOptions(options);
+      this.setCoords();
+
+      if (options.sourcePath) {
+        this.setSourcePath(options.sourcePath);
+      }
+    },
+
+    /**
+     * Calculate width and height based on paths contained
+     */
+    parseDimensionsFromPaths: function(options) {
+      var points, p, xC = [], yC = [], path, height, width,
+          m;
+      for (var j = this.paths.length; j--;) {
+        path = this.paths[j];
+        height = path.height + path.strokeWidth;
+        width = path.width + path.strokeWidth;
+        points = [
+          { x: path.left, y: path.top },
+          { x: path.left + width, y: path.top },
+          { x: path.left, y: path.top + height },
+          { x: path.left + width, y: path.top + height }
+        ];
+        m = this.paths[j].transformMatrix;
+        for (var i = 0; i < points.length; i++) {
+          p = points[i];
+          if (m) {
+            p = fabric.util.transformPoint(p, m, false);
+          }
+          xC.push(p.x);
+          yC.push(p.y);
+        }
+      }
+      options.width = Math.max.apply(null, xC);
+      options.height = Math.max.apply(null, yC);
+    },
+
+    /**
+     * Renders this group on a specified context
+     * @param {CanvasRenderingContext2D} ctx Context to render this instance on
+     */
+    render: function(ctx) {
+      // do not render if object is not visible
+      if (!this.visible) {
+        return;
+      }
+
+      ctx.save();
+
+      if (this.transformMatrix) {
+        ctx.transform.apply(ctx, this.transformMatrix);
+      }
+      this.transform(ctx);
+
+      this._setShadow(ctx);
+      this.clipTo && fabric.util.clipContext(this, ctx);
+      ctx.translate(-this.width / 2, -this.height / 2);
+      for (var i = 0, l = this.paths.length; i < l; ++i) {
+        this.paths[i].render(ctx, true);
+      }
+      this.clipTo && ctx.restore();
+      ctx.restore();
+    },
+
+    /**
+     * Sets certain property to a certain value
+     * @param {String} prop
+     * @param {*} value
+     * @return {fabric.PathGroup} thisArg
+     */
+    _set: function(prop, value) {
+
+      if (prop === 'fill' && value && this.isSameColor()) {
+        var i = this.paths.length;
+        while (i--) {
+          this.paths[i]._set(prop, value);
+        }
+      }
+
+      return this.callSuper('_set', prop, value);
+    },
+
+    /**
+     * Returns object representation of this path group
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      var o = extend(parentToObject.call(this, ['sourcePath'].concat(propertiesToInclude)), {
+        paths: invoke(this.getObjects(), 'toObject', propertiesToInclude)
+      });
+      return o;
+    },
+
+    /**
+     * Returns dataless object representation of this path group
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} dataless object representation of an instance
+     */
+    toDatalessObject: function(propertiesToInclude) {
+      var o = this.toObject(propertiesToInclude);
+      if (this.sourcePath) {
+        o.paths = this.sourcePath;
+      }
+      return o;
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var objects = this.getObjects(),
+          p = this.getPointByOrigin('left', 'top'),
+          translatePart = 'translate(' + p.x + ' ' + p.y + ')',
+          markup = this._createBaseSVGMarkup();
+      markup.push(
+        '<g ', this.getSvgId(),
+        'style="', this.getSvgStyles(), '" ',
+        'transform="', this.getSvgTransformMatrix(), translatePart, this.getSvgTransform(), '" ',
+        '>\n'
+      );
+
+      for (var i = 0, len = objects.length; i < len; i++) {
+        markup.push('\t', objects[i].toSVG(reviver));
+      }
+      markup.push('</g>\n');
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns a string representation of this path group
+     * @return {String} string representation of an object
+     */
+    toString: function() {
+      return '#<fabric.PathGroup (' + this.complexity() +
+        '): { top: ' + this.top + ', left: ' + this.left + ' }>';
+    },
+
+    /**
+     * Returns true if all paths in this group are of same color
+     * @return {Boolean} true if all paths are of the same color (`fill`)
+     */
+    isSameColor: function() {
+      var firstPathFill = this.getObjects()[0].get('fill') || '';
+      if (typeof firstPathFill !== 'string') {
+        return false;
+      }
+      firstPathFill = firstPathFill.toLowerCase();
+      return this.getObjects().every(function(path) {
+        var pathFill = path.get('fill') || '';
+        return typeof pathFill === 'string' && (pathFill).toLowerCase() === firstPathFill;
+      });
+    },
+
+    /**
+     * Returns number representation of object's complexity
+     * @return {Number} complexity
+     */
+    complexity: function() {
+      return this.paths.reduce(function(total, path) {
+        return total + ((path && path.complexity) ? path.complexity() : 0);
+      }, 0);
+    },
+
+    /**
+     * Returns all paths in this path group
+     * @return {Array} array of path objects included in this path group
+     */
+    getObjects: function() {
+      return this.paths;
+    }
+  });
+
+  /**
+   * Creates fabric.PathGroup instance from an object representation
+   * @static
+   * @memberOf fabric.PathGroup
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.PathGroup instance is created
+   */
+  fabric.PathGroup.fromObject = function(object, callback) {
+    // remove this pattern from 2.0 accepts only object
+    if (typeof object.paths === 'string') {
+      fabric.loadSVGFromURL(object.paths, function (elements) {
+
+        var pathUrl = object.paths;
+        delete object.paths;
+
+        var pathGroup = fabric.util.groupSVGElements(elements, object, pathUrl);
+
+        callback(pathGroup);
+      });
+    }
+    else {
+      fabric.util.enlivenObjects(object.paths, function(enlivenedObjects) {
+        delete object.paths;
+        callback(new fabric.PathGroup(enlivenedObjects, object));
+      });
+    }
+  };
+
+  /**
+   * Indicates that instances of this type are async
+   * @static
+   * @memberOf fabric.PathGroup
+   * @type Boolean
+   * @default
+   */
+  fabric.PathGroup.async = true;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      min = fabric.util.array.min,
+      max = fabric.util.array.max,
+      invoke = fabric.util.array.invoke;
+
+  if (fabric.Group) {
+    return;
+  }
+
+  // lock-related properties, for use in fabric.Group#get
+  // to enable locking behavior on group
+  // when one of its objects has lock-related properties set
+  var _lockProperties = {
+    lockMovementX:  true,
+    lockMovementY:  true,
+    lockRotation:   true,
+    lockScalingX:   true,
+    lockScalingY:   true,
+    lockUniScaling: true
+  };
+
+  /**
+   * Group class
+   * @class fabric.Group
+   * @extends fabric.Object
+   * @mixes fabric.Collection
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}
+   * @see {@link fabric.Group#initialize} for constructor definition
+   */
+  fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'group',
+
+    /**
+     * Width of stroke
+     * @type Number
+     * @default
+     */
+    strokeWidth: 0,
+
+    /**
+     * Indicates if click events should also check for subtargets
+     * @type Boolean
+     * @default
+     */
+    subTargetCheck: false,
+
+    /**
+     * Constructor
+     * @param {Object} objects Group objects
+     * @param {Object} [options] Options object
+     * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already.
+     * @return {Object} thisArg
+     */
+    initialize: function(objects, options, isAlreadyGrouped) {
+      options = options || { };
+
+      this._objects = [];
+      // if objects enclosed in a group have been grouped already,
+      // we cannot change properties of objects.
+      // Thus we need to set options to group without objects,
+      // because delegatedProperties propagate to objects.
+      isAlreadyGrouped && this.callSuper('initialize', options);
+
+      this._objects = objects || [];
+      for (var i = this._objects.length; i--; ) {
+        this._objects[i].group = this;
+      }
+
+      this.originalState = { };
+
+      if (options.originX) {
+        this.originX = options.originX;
+      }
+      if (options.originY) {
+        this.originY = options.originY;
+      }
+
+      if (isAlreadyGrouped) {
+        // do not change coordinate of objects enclosed in a group,
+        // because objects coordinate system have been group coodinate system already.
+        this._updateObjectsCoords(true);
+      }
+      else {
+        this._calcBounds();
+        this._updateObjectsCoords();
+        this.callSuper('initialize', options);
+      }
+
+      this.setCoords();
+      this.saveCoords();
+    },
+
+    /**
+     * @private
+     * @param {Boolean} [skipCoordsChange] if true, coordinates of objects enclosed in a group do not change
+     */
+    _updateObjectsCoords: function(skipCoordsChange) {
+      for (var i = this._objects.length; i--; ){
+        this._updateObjectCoords(this._objects[i], skipCoordsChange);
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} object
+     * @param {Boolean} [skipCoordsChange] if true, coordinates of object dose not change
+     */
+    _updateObjectCoords: function(object, skipCoordsChange) {
+      // do not display corners of objects enclosed in a group
+      object.__origHasControls = object.hasControls;
+      object.hasControls = false;
+
+      if (skipCoordsChange) {
+        return;
+      }
+
+      var objectLeft = object.getLeft(),
+          objectTop = object.getTop(),
+          center = this.getCenterPoint();
+
+      object.set({
+        originalLeft: objectLeft,
+        originalTop: objectTop,
+        left: objectLeft - center.x,
+        top: objectTop - center.y
+      });
+      object.setCoords();
+    },
+
+    /**
+     * Returns string represenation of a group
+     * @return {String}
+     */
+    toString: function() {
+      return '#<fabric.Group: (' + this.complexity() + ')>';
+    },
+
+    /**
+     * Adds an object to a group; Then recalculates group's dimension, position.
+     * @param {Object} object
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    addWithUpdate: function(object) {
+      this._restoreObjectsState();
+      fabric.util.resetObjectTransform(this);
+      if (object) {
+        this._objects.push(object);
+        object.group = this;
+        object._set('canvas', this.canvas);
+      }
+      // since _restoreObjectsState set objects inactive
+      this.forEachObject(this._setObjectActive, this);
+      this._calcBounds();
+      this._updateObjectsCoords();
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _setObjectActive: function(object) {
+      object.set('active', true);
+      object.group = this;
+    },
+
+    /**
+     * Removes an object from a group; Then recalculates group's dimension, position.
+     * @param {Object} object
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    removeWithUpdate: function(object) {
+      this._restoreObjectsState();
+      fabric.util.resetObjectTransform(this);
+      // since _restoreObjectsState set objects inactive
+      this.forEachObject(this._setObjectActive, this);
+
+      this.remove(object);
+      this._calcBounds();
+      this._updateObjectsCoords();
+
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _onObjectAdded: function(object) {
+      object.group = this;
+      object._set('canvas', this.canvas);
+    },
+
+    /**
+     * @private
+     */
+    _onObjectRemoved: function(object) {
+      delete object.group;
+      object.set('active', false);
+    },
+
+    /**
+     * Properties that are delegated to group objects when reading/writing
+     * @param {Object} delegatedProperties
+     */
+    delegatedProperties: {
+      fill:             true,
+      stroke:           true,
+      strokeWidth:      true,
+      fontFamily:       true,
+      fontWeight:       true,
+      fontSize:         true,
+      fontStyle:        true,
+      lineHeight:       true,
+      textDecoration:   true,
+      textAlign:        true,
+      backgroundColor:  true
+    },
+
+    /**
+     * @private
+     */
+    _set: function(key, value) {
+      var i = this._objects.length;
+
+      if (this.delegatedProperties[key] || key === 'canvas') {
+        while (i--) {
+          this._objects[i].set(key, value);
+        }
+      }
+      else {
+        while (i--) {
+          this._objects[i].setOnGroup(key, value);
+        }
+      }
+
+      this.callSuper('_set', key, value);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return extend(this.callSuper('toObject', propertiesToInclude), {
+        objects: invoke(this._objects, 'toObject', propertiesToInclude)
+      });
+    },
+
+    /**
+     * Renders instance on a given context
+     * @param {CanvasRenderingContext2D} ctx context to render instance on
+     */
+    render: function(ctx) {
+      // do not render if object is not visible
+      if (!this.visible) {
+        return;
+      }
+
+      ctx.save();
+      if (this.transformMatrix) {
+        ctx.transform.apply(ctx, this.transformMatrix);
+      }
+      this.transform(ctx);
+      this._setShadow(ctx);
+      this.clipTo && fabric.util.clipContext(this, ctx);
+      this._transformDone = true;
+      // the array is now sorted in order of highest first, so start from end
+      for (var i = 0, len = this._objects.length; i < len; i++) {
+        this._renderObject(this._objects[i], ctx);
+      }
+
+      this.clipTo && ctx.restore();
+      ctx.restore();
+      this._transformDone = false;
+    },
+
+    /**
+     * Renders controls and borders for the object
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} [noTransform] When true, context is not transformed
+     */
+    _renderControls: function(ctx, noTransform) {
+      this.callSuper('_renderControls', ctx, noTransform);
+      for (var i = 0, len = this._objects.length; i < len; i++) {
+        this._objects[i]._renderControls(ctx);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _renderObject: function(object, ctx) {
+      // do not render if object is not visible
+      if (!object.visible) {
+        return;
+      }
+
+      var originalHasRotatingPoint = object.hasRotatingPoint;
+      object.hasRotatingPoint = false;
+      object.render(ctx);
+      object.hasRotatingPoint = originalHasRotatingPoint;
+    },
+
+    /**
+     * Retores original state of each of group objects (original state is that which was before group was created).
+     * @private
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    _restoreObjectsState: function() {
+      this._objects.forEach(this._restoreObjectState, this);
+      return this;
+    },
+
+    /**
+     * Realises the transform from this group onto the supplied object
+     * i.e. it tells you what would happen if the supplied object was in
+     * the group, and then the group was destroyed. It mutates the supplied
+     * object.
+     * @param {fabric.Object} object
+     * @return {fabric.Object} transformedObject
+     */
+    realizeTransform: function(object) {
+      var matrix = object.calcTransformMatrix(),
+          options = fabric.util.qrDecompose(matrix),
+          center = new fabric.Point(options.translateX, options.translateY);
+      object.scaleX = options.scaleX;
+      object.scaleY = options.scaleY;
+      object.skewX = options.skewX;
+      object.skewY = options.skewY;
+      object.angle = options.angle;
+      object.flipX = false;
+      object.flipY = false;
+      object.setPositionByOrigin(center, 'center', 'center');
+      return object;
+    },
+
+    /**
+     * Restores original state of a specified object in group
+     * @private
+     * @param {fabric.Object} object
+     * @return {fabric.Group} thisArg
+     */
+    _restoreObjectState: function(object) {
+      this.realizeTransform(object);
+      object.setCoords();
+      object.hasControls = object.__origHasControls;
+      delete object.__origHasControls;
+      object.set('active', false);
+      delete object.group;
+
+      return this;
+    },
+
+    /**
+     * Destroys a group (restoring state of its objects)
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    destroy: function() {
+      return this._restoreObjectsState();
+    },
+
+    /**
+     * Saves coordinates of this instance (to be used together with `hasMoved`)
+     * @saveCoords
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    saveCoords: function() {
+      this._originalLeft = this.get('left');
+      this._originalTop = this.get('top');
+      return this;
+    },
+
+    /**
+     * Checks whether this group was moved (since `saveCoords` was called last)
+     * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called)
+     */
+    hasMoved: function() {
+      return this._originalLeft !== this.get('left') ||
+             this._originalTop !== this.get('top');
+    },
+
+    /**
+     * Sets coordinates of all group objects
+     * @return {fabric.Group} thisArg
+     * @chainable
+     */
+    setObjectsCoords: function() {
+      this.forEachObject(function(object) {
+        object.setCoords();
+      });
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _calcBounds: function(onlyWidthHeight) {
+      var aX = [],
+          aY = [],
+          o, prop,
+          props = ['tr', 'br', 'bl', 'tl'],
+          i = 0, iLen = this._objects.length,
+          j, jLen = props.length;
+
+      for ( ; i < iLen; ++i) {
+        o = this._objects[i];
+        o.setCoords();
+        for (j = 0; j < jLen; j++) {
+          prop = props[j];
+          aX.push(o.oCoords[prop].x);
+          aY.push(o.oCoords[prop].y);
+        }
+      }
+
+      this.set(this._getBounds(aX, aY, onlyWidthHeight));
+    },
+
+    /**
+     * @private
+     */
+    _getBounds: function(aX, aY, onlyWidthHeight) {
+      var ivt = fabric.util.invertTransform(this.getViewportTransform()),
+          minXY = fabric.util.transformPoint(new fabric.Point(min(aX), min(aY)), ivt),
+          maxXY = fabric.util.transformPoint(new fabric.Point(max(aX), max(aY)), ivt),
+          obj = {
+            width: (maxXY.x - minXY.x) || 0,
+            height: (maxXY.y - minXY.y) || 0
+          };
+
+      if (!onlyWidthHeight) {
+        obj.left = minXY.x || 0;
+        obj.top = minXY.y || 0;
+        if (this.originX === 'center') {
+          obj.left += obj.width / 2;
+        }
+        if (this.originX === 'right') {
+          obj.left += obj.width;
+        }
+        if (this.originY === 'center') {
+          obj.top += obj.height / 2;
+        }
+        if (this.originY === 'bottom') {
+          obj.top += obj.height;
+        }
+      }
+      return obj;
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns svg representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup();
+      markup.push(
+        '<g ', this.getSvgId(), 'transform="',
+        /* avoiding styles intentionally */
+        this.getSvgTransform(),
+        this.getSvgTransformMatrix(),
+        '" style="',
+        this.getSvgFilter(),
+        '">\n'
+      );
+
+      for (var i = 0, len = this._objects.length; i < len; i++) {
+        markup.push('\t', this._objects[i].toSVG(reviver));
+      }
+
+      markup.push('</g>\n');
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns requested property
+     * @param {String} prop Property to get
+     * @return {*}
+     */
+    get: function(prop) {
+      if (prop in _lockProperties) {
+        if (this[prop]) {
+          return this[prop];
+        }
+        else {
+          for (var i = 0, len = this._objects.length; i < len; i++) {
+            if (this._objects[i][prop]) {
+              return true;
+            }
+          }
+          return false;
+        }
+      }
+      else {
+        if (prop in this.delegatedProperties) {
+          return this._objects[0] && this._objects[0].get(prop);
+        }
+        return this[prop];
+      }
+    }
+  });
+
+  /**
+   * Returns {@link fabric.Group} instance from an object representation
+   * @static
+   * @memberOf fabric.Group
+   * @param {Object} object Object to create a group from
+   * @param {Function} [callback] Callback to invoke when an group instance is created
+   */
+  fabric.Group.fromObject = function(object, callback) {
+    fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {
+      delete object.objects;
+      callback && callback(new fabric.Group(enlivenedObjects, object, true));
+    });
+  };
+
+  /**
+   * Indicates that instances of this type are async
+   * @static
+   * @memberOf fabric.Group
+   * @type Boolean
+   * @default
+   */
+  fabric.Group.async = true;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var extend = fabric.util.object.extend;
+
+  if (!global.fabric) {
+    global.fabric = { };
+  }
+
+  if (global.fabric.Image) {
+    fabric.warn('fabric.Image is already defined.');
+    return;
+  }
+
+  var stateProperties = fabric.Object.prototype.stateProperties.concat();
+  stateProperties.push(
+    'alignX',
+    'alignY',
+    'meetOrSlice'
+  );
+
+  /**
+   * Image class
+   * @class fabric.Image
+   * @extends fabric.Object
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}
+   * @see {@link fabric.Image#initialize} for constructor definition
+   */
+  fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'image',
+
+    /**
+     * crossOrigin value (one of "", "anonymous", "use-credentials")
+     * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes
+     * @type String
+     * @default
+     */
+    crossOrigin: '',
+
+    /**
+     * AlignX value, part of preserveAspectRatio (one of "none", "mid", "min", "max")
+     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
+     * This parameter defines how the picture is aligned to its viewport when image element width differs from image width.
+     * @type String
+     * @default
+     */
+    alignX: 'none',
+
+    /**
+     * AlignY value, part of preserveAspectRatio (one of "none", "mid", "min", "max")
+     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
+     * This parameter defines how the picture is aligned to its viewport when image element height differs from image height.
+     * @type String
+     * @default
+     */
+    alignY: 'none',
+
+    /**
+     * meetOrSlice value, part of preserveAspectRatio  (one of "meet", "slice").
+     * if meet the image is always fully visibile, if slice the viewport is always filled with image.
+     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
+     * @type String
+     * @default
+     */
+    meetOrSlice: 'meet',
+
+    /**
+     * Width of a stroke.
+     * For image quality a stroke multiple of 2 gives better results.
+     * @type Number
+     * @default
+     */
+    strokeWidth: 0,
+
+    /**
+     * private
+     * contains last value of scaleX to detect
+     * if the Image got resized after the last Render
+     * @type Number
+     */
+    _lastScaleX: 1,
+
+    /**
+     * private
+     * contains last value of scaleY to detect
+     * if the Image got resized after the last Render
+     * @type Number
+     */
+    _lastScaleY: 1,
+
+    /**
+     * minimum scale factor under which any resizeFilter is triggered to resize the image
+     * 0 will disable the automatic resize. 1 will trigger automatically always.
+     * number bigger than 1 can be used in case we want to scale with some filter above
+     * the natural image dimensions
+     * @type Number
+     */
+    minimumScaleTrigger: 0.5,
+
+    /**
+     * List of properties to consider when checking if
+     * state of an object is changed ({@link fabric.Object#hasStateChanged})
+     * as well as for history (undo/redo) purposes
+     * @type Array
+     */
+    stateProperties: stateProperties,
+
+    /**
+     * Constructor
+     * @param {HTMLImageElement | String} element Image element
+     * @param {Object} [options] Options object
+     * @param {function} [callback] callback function to call after eventual filters applied.
+     * @return {fabric.Image} thisArg
+     */
+    initialize: function(element, options, callback) {
+      options || (options = { });
+      this.filters = [];
+      this.resizeFilters = [];
+      this.callSuper('initialize', options);
+      this._initElement(element, options, callback);
+    },
+
+    /**
+     * Returns image element which this instance if based on
+     * @return {HTMLImageElement} Image element
+     */
+    getElement: function() {
+      return this._element;
+    },
+
+    /**
+     * Sets image element for this instance to a specified one.
+     * If filters defined they are applied to new image.
+     * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.
+     * @param {HTMLImageElement} element
+     * @param {Function} [callback] Callback is invoked when all filters have been applied and new image is generated
+     * @param {Object} [options] Options object
+     * @return {fabric.Image} thisArg
+     * @chainable
+     */
+    setElement: function(element, callback, options) {
+
+      var _callback, _this;
+
+      this._element = element;
+      this._originalElement = element;
+      this._initConfig(options);
+
+      if (this.resizeFilters.length === 0) {
+        _callback = callback;
+      }
+      else {
+        _this = this;
+        _callback = function() {
+          _this.applyFilters(callback, _this.resizeFilters, _this._filteredEl || _this._originalElement, true);
+        };
+      }
+
+      if (this.filters.length !== 0) {
+        this.applyFilters(_callback);
+      }
+      else if (_callback) {
+        _callback(this);
+      }
+
+      return this;
+    },
+
+    /**
+     * Sets crossOrigin value (on an instance and corresponding image element)
+     * @return {fabric.Image} thisArg
+     * @chainable
+     */
+    setCrossOrigin: function(value) {
+      this.crossOrigin = value;
+      this._element.crossOrigin = value;
+
+      return this;
+    },
+
+    /**
+     * Returns original size of an image
+     * @return {Object} Object with "width" and "height" properties
+     */
+    getOriginalSize: function() {
+      var element = this.getElement();
+      return {
+        width: element.width,
+        height: element.height
+      };
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _stroke: function(ctx) {
+      if (!this.stroke || this.strokeWidth === 0) {
+        return;
+      }
+      var w = this.width / 2, h = this.height / 2;
+      ctx.beginPath();
+      ctx.moveTo(-w, -h);
+      ctx.lineTo(w, -h);
+      ctx.lineTo(w, h);
+      ctx.lineTo(-w, h);
+      ctx.lineTo(-w, -h);
+      ctx.closePath();
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderDashedStroke: function(ctx) {
+      var x = -this.width / 2,
+          y = -this.height / 2,
+          w = this.width,
+          h = this.height;
+
+      ctx.save();
+      this._setStrokeStyles(ctx);
+
+      ctx.beginPath();
+      fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);
+      fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);
+      ctx.closePath();
+      ctx.restore();
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      var filters = [], resizeFilters = [],
+          scaleX = 1, scaleY = 1;
+
+      this.filters.forEach(function(filterObj) {
+        if (filterObj) {
+          if (filterObj.type === 'Resize') {
+            scaleX *= filterObj.scaleX;
+            scaleY *= filterObj.scaleY;
+          }
+          filters.push(filterObj.toObject());
+        }
+      });
+
+      this.resizeFilters.forEach(function(filterObj) {
+        filterObj && resizeFilters.push(filterObj.toObject());
+      });
+      var object = extend(
+        this.callSuper(
+          'toObject',
+          ['crossOrigin', 'alignX', 'alignY', 'meetOrSlice'].concat(propertiesToInclude)
+        ), {
+          src: this.getSrc(),
+          filters: filters,
+          resizeFilters: resizeFilters,
+        });
+
+      object.width /= scaleX;
+      object.height /= scaleY;
+
+      return object;
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2,
+          preserveAspectRatio = 'none', filtered = true;
+      if (this.group && this.group.type === 'path-group') {
+        x = this.left;
+        y = this.top;
+      }
+      if (this.alignX !== 'none' && this.alignY !== 'none') {
+        preserveAspectRatio = 'x' + this.alignX + 'Y' + this.alignY + ' ' + this.meetOrSlice;
+      }
+      markup.push(
+        '<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n',
+          '<image ', this.getSvgId(), 'xlink:href="', this.getSvgSrc(filtered),
+            '" x="', x, '" y="', y,
+            '" style="', this.getSvgStyles(),
+            // we're essentially moving origin of transformation from top/left corner to the center of the shape
+            // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
+            // so that object's center aligns with container's left/top
+            '" width="', this.width,
+            '" height="', this.height,
+            '" preserveAspectRatio="', preserveAspectRatio, '"',
+          '></image>\n'
+      );
+
+      if (this.stroke || this.strokeDashArray) {
+        var origFill = this.fill;
+        this.fill = null;
+        markup.push(
+          '<rect ',
+            'x="', x, '" y="', y,
+            '" width="', this.width, '" height="', this.height,
+            '" style="', this.getSvgStyles(),
+          '"/>\n'
+        );
+        this.fill = origFill;
+      }
+
+      markup.push('</g>\n');
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Returns source of an image
+     * @param {Boolean} filtered indicates if the src is needed for svg
+     * @return {String} Source of an image
+     */
+    getSrc: function(filtered) {
+      var element = filtered ? this._element : this._originalElement;
+      if (element) {
+        return fabric.isLikelyNode ? element._src : element.src;
+      }
+      else {
+        return this.src || '';
+      }
+    },
+
+    /**
+     * Sets source of an image
+     * @param {String} src Source string (URL)
+     * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied)
+     * @param {Object} [options] Options object
+     * @return {fabric.Image} thisArg
+     * @chainable
+     */
+    setSrc: function(src, callback, options) {
+      fabric.util.loadImage(src, function(img) {
+        return this.setElement(img, callback, options);
+      }, this, options && options.crossOrigin);
+    },
+
+    /**
+     * Returns string representation of an instance
+     * @return {String} String representation of an instance
+     */
+    toString: function() {
+      return '#<fabric.Image: { src: "' + this.getSrc() + '" }>';
+    },
+
+    /**
+     * Applies filters assigned to this image (from "filters" array)
+     * @method applyFilters
+     * @param {Function} callback Callback is invoked when all filters have been applied and new image is generated
+     * @param {Array} filters to be applied
+     * @param {fabric.Image} imgElement image to filter ( default to this._element )
+     * @param {Boolean} forResizing
+     * @return {CanvasElement} canvasEl to be drawn immediately
+     * @chainable
+     */
+    applyFilters: function(callback, filters, imgElement, forResizing) {
+
+      filters = filters || this.filters;
+      imgElement = imgElement || this._originalElement;
+
+      if (!imgElement) {
+        return;
+      }
+
+      var replacement = fabric.util.createImage(),
+          retinaScaling = this.canvas ? this.canvas.getRetinaScaling() : fabric.devicePixelRatio,
+          minimumScale = this.minimumScaleTrigger / retinaScaling,
+          _this = this, scaleX, scaleY;
+
+      if (filters.length === 0) {
+        this._element = imgElement;
+        callback && callback(this);
+        return imgElement;
+      }
+
+      var canvasEl = fabric.util.createCanvasElement();
+      canvasEl.width = imgElement.width;
+      canvasEl.height = imgElement.height;
+      canvasEl.getContext('2d').drawImage(imgElement, 0, 0, imgElement.width, imgElement.height);
+
+      filters.forEach(function(filter) {
+        if (!filter) {
+          return;
+        }
+        if (forResizing) {
+          scaleX = _this.scaleX < minimumScale ? _this.scaleX : 1;
+          scaleY = _this.scaleY < minimumScale ? _this.scaleY : 1;
+          if (scaleX * retinaScaling < 1) {
+            scaleX *= retinaScaling;
+          }
+          if (scaleY * retinaScaling < 1) {
+            scaleY *= retinaScaling;
+          }
+        }
+        else {
+          scaleX = filter.scaleX;
+          scaleY = filter.scaleY;
+        }
+        filter.applyTo(canvasEl, scaleX, scaleY);
+        if (!forResizing && filter.type === 'Resize') {
+          _this.width *= filter.scaleX;
+          _this.height *= filter.scaleY;
+        }
+      });
+
+      /** @ignore */
+      replacement.width = canvasEl.width;
+      replacement.height = canvasEl.height;
+      if (fabric.isLikelyNode) {
+        replacement.src = canvasEl.toBuffer(undefined, fabric.Image.pngCompression);
+        // onload doesn't fire in some node versions, so we invoke callback manually
+        _this._element = replacement;
+        !forResizing && (_this._filteredEl = replacement);
+        callback && callback(_this);
+      }
+      else {
+        replacement.onload = function() {
+          _this._element = replacement;
+          !forResizing && (_this._filteredEl = replacement);
+          callback && callback(_this);
+          replacement.onload = canvasEl = null;
+        };
+        replacement.src = canvasEl.toDataURL('image/png');
+      }
+      return canvasEl;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    _render: function(ctx, noTransform) {
+      var x, y, imageMargins = this._findMargins(), elementToDraw;
+
+      x = (noTransform ? this.left : -this.width / 2);
+      y = (noTransform ? this.top : -this.height / 2);
+
+      if (this.meetOrSlice === 'slice') {
+        ctx.beginPath();
+        ctx.rect(x, y, this.width, this.height);
+        ctx.clip();
+      }
+
+      if (this.isMoving === false && this.resizeFilters.length && this._needsResize()) {
+        this._lastScaleX = this.scaleX;
+        this._lastScaleY = this.scaleY;
+        elementToDraw = this.applyFilters(null, this.resizeFilters, this._filteredEl || this._originalElement, true);
+      }
+      else {
+        elementToDraw = this._element;
+      }
+      elementToDraw && ctx.drawImage(elementToDraw,
+                                     x + imageMargins.marginX,
+                                     y + imageMargins.marginY,
+                                     imageMargins.width,
+                                     imageMargins.height
+                                    );
+
+      this._stroke(ctx);
+      this._renderStroke(ctx);
+    },
+
+    /**
+     * @private, needed to check if image needs resize
+     */
+    _needsResize: function() {
+      return (this.scaleX !== this._lastScaleX || this.scaleY !== this._lastScaleY);
+    },
+
+    /**
+     * @private
+     */
+    _findMargins: function() {
+      var width = this.width, height = this.height, scales,
+          scale, marginX = 0, marginY = 0;
+
+      if (this.alignX !== 'none' || this.alignY !== 'none') {
+        scales = [this.width / this._element.width, this.height / this._element.height];
+        scale = this.meetOrSlice === 'meet'
+                ? Math.min.apply(null, scales) : Math.max.apply(null, scales);
+        width = this._element.width * scale;
+        height = this._element.height * scale;
+        if (this.alignX === 'Mid') {
+          marginX = (this.width - width) / 2;
+        }
+        if (this.alignX === 'Max') {
+          marginX = this.width - width;
+        }
+        if (this.alignY === 'Mid') {
+          marginY = (this.height - height) / 2;
+        }
+        if (this.alignY === 'Max') {
+          marginY = this.height - height;
+        }
+      }
+      return {
+        width:  width,
+        height: height,
+        marginX: marginX,
+        marginY: marginY
+      };
+    },
+
+    /**
+     * @private
+     */
+    _resetWidthHeight: function() {
+      var element = this.getElement();
+
+      this.set('width', element.width);
+      this.set('height', element.height);
+    },
+
+    /**
+     * The Image class's initialization method. This method is automatically
+     * called by the constructor.
+     * @private
+     * @param {HTMLImageElement|String} element The element representing the image
+     * @param {Object} [options] Options object
+     */
+    _initElement: function(element, options, callback) {
+      this.setElement(fabric.util.getById(element), callback, options);
+      fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS);
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Options object
+     */
+    _initConfig: function(options) {
+      options || (options = { });
+      this.setOptions(options);
+      this._setWidthHeight(options);
+      if (this._element && this.crossOrigin) {
+        this._element.crossOrigin = this.crossOrigin;
+      }
+    },
+
+    /**
+     * @private
+     * @param {Array} filters to be initialized
+     * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created
+     */
+    _initFilters: function(filters, callback) {
+      if (filters && filters.length) {
+        fabric.util.enlivenObjects(filters, function(enlivenedObjects) {
+          callback && callback(enlivenedObjects);
+        }, 'fabric.Image.filters');
+      }
+      else {
+        callback && callback();
+      }
+    },
+
+    /**
+     * @private
+     * @param {Object} [options] Object with width/height properties
+     */
+    _setWidthHeight: function(options) {
+      this.width = 'width' in options
+        ? options.width
+        : (this.getElement()
+            ? this.getElement().width || 0
+            : 0);
+
+      this.height = 'height' in options
+        ? options.height
+        : (this.getElement()
+            ? this.getElement().height || 0
+            : 0);
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity of this instance
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /**
+   * Default CSS class name for canvas
+   * @static
+   * @type String
+   * @default
+   */
+  fabric.Image.CSS_CANVAS = 'canvas-img';
+
+  /**
+   * Alias for getSrc
+   * @static
+   */
+  fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;
+
+  /**
+   * Creates an instance of fabric.Image from its object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @param {Function} callback Callback to invoke when an image instance is created
+   */
+  fabric.Image.fromObject = function(object, callback) {
+    fabric.util.loadImage(object.src, function(img) {
+      fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) {
+        object.filters = filters || [];
+        fabric.Image.prototype._initFilters.call(object, object.resizeFilters, function(resizeFilters) {
+          object.resizeFilters = resizeFilters || [];
+          return new fabric.Image(img, object, callback);
+        });
+      });
+    }, null, object.crossOrigin);
+  };
+
+  /**
+   * Creates an instance of fabric.Image from an URL string
+   * @static
+   * @param {String} url URL to create an image from
+   * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)
+   * @param {Object} [imgOptions] Options object
+   */
+  fabric.Image.fromURL = function(url, callback, imgOptions) {
+    fabric.util.loadImage(url, function(img) {
+      callback && callback(new fabric.Image(img, imgOptions));
+    }, null, imgOptions && imgOptions.crossOrigin);
+  };
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})
+   * @static
+   * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement}
+   */
+  fabric.Image.ATTRIBUTE_NAMES =
+    fabric.SHARED_ATTRIBUTES.concat('x y width height preserveAspectRatio xlink:href'.split(' '));
+
+  /**
+   * Returns {@link fabric.Image} instance from an SVG element
+   * @static
+   * @param {SVGElement} element Element to parse
+   * @param {Function} callback Callback to execute when fabric.Image object is created
+   * @param {Object} [options] Options object
+   * @return {fabric.Image} Instance of fabric.Image
+   */
+  fabric.Image.fromElement = function(element, callback, options) {
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES),
+        preserveAR;
+
+    if (parsedAttributes.preserveAspectRatio) {
+      preserveAR = fabric.util.parsePreserveAspectRatioAttribute(parsedAttributes.preserveAspectRatio);
+      extend(parsedAttributes, preserveAR);
+    }
+
+    fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,
+      extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Indicates that instances of this type are async
+   * @static
+   * @type Boolean
+   * @default
+   */
+  fabric.Image.async = true;
+
+  /**
+   * Indicates compression level used when generating PNG under Node (in applyFilters). Any of 0-9
+   * @static
+   * @type Number
+   * @default
+   */
+  fabric.Image.pngCompression = 1;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
+
+  /**
+   * @private
+   * @return {Number} angle value
+   */
+  _getAngleValueForStraighten: function() {
+    var angle = this.getAngle() % 360;
+    if (angle > 0) {
+      return Math.round((angle - 1) / 90) * 90;
+    }
+    return Math.round(angle / 90) * 90;
+  },
+
+  /**
+   * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  straighten: function() {
+    this.setAngle(this._getAngleValueForStraighten());
+    return this;
+  },
+
+  /**
+   * Same as {@link fabric.Object.prototype.straighten} but with animation
+   * @param {Object} callbacks Object with callback functions
+   * @param {Function} [callbacks.onComplete] Invoked on completion
+   * @param {Function} [callbacks.onChange] Invoked on every step of animation
+   * @return {fabric.Object} thisArg
+   * @chainable
+   */
+  fxStraighten: function(callbacks) {
+    callbacks = callbacks || { };
+
+    var empty = function() { },
+        onComplete = callbacks.onComplete || empty,
+        onChange = callbacks.onChange || empty,
+        _this = this;
+
+    fabric.util.animate({
+      startValue: this.get('angle'),
+      endValue: this._getAngleValueForStraighten(),
+      duration: this.FX_DURATION,
+      onChange: function(value) {
+        _this.setAngle(value);
+        onChange();
+      },
+      onComplete: function() {
+        _this.setCoords();
+        onComplete();
+      },
+      onStart: function() {
+        _this.set('active', false);
+      }
+    });
+
+    return this;
+  }
+});
+
+fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
+
+  /**
+   * Straightens object, then rerenders canvas
+   * @param {fabric.Object} object Object to straighten
+   * @return {fabric.Canvas} thisArg
+   * @chainable
+   */
+  straightenObject: function (object) {
+    object.straighten();
+    this.renderAll();
+    return this;
+  },
+
+  /**
+   * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated
+   * @param {fabric.Object} object Object to straighten
+   * @return {fabric.Canvas} thisArg
+   * @chainable
+   */
+  fxStraightenObject: function (object) {
+    object.fxStraighten({
+      onChange: this.renderAll.bind(this)
+    });
+    return this;
+  }
+});
+
+
+/**
+ * @namespace fabric.Image.filters
+ * @memberOf fabric.Image
+ * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters}
+ * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+ */
+fabric.Image.filters = fabric.Image.filters || { };
+
+/**
+ * Root filter class from which all filter classes inherit from
+ * @class fabric.Image.filters.BaseFilter
+ * @memberOf fabric.Image.filters
+ */
+fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ {
+
+  /**
+   * Filter type
+   * @param {String} type
+   * @default
+   */
+  type: 'BaseFilter',
+
+  /**
+   * Constructor
+   * @param {Object} [options] Options object
+   */
+  initialize: function(options) {
+    if (options) {
+      this.setOptions(options);
+    }
+  },
+
+  /**
+   * Sets filter's properties from options
+   * @param {Object} [options] Options object
+   */
+  setOptions: function(options) {
+    for (var prop in options) {
+      this[prop] = options[prop];
+    }
+  },
+
+  /**
+   * Returns object representation of an instance
+   * @return {Object} Object representation of an instance
+   */
+  toObject: function() {
+    return { type: this.type };
+  },
+
+  /**
+   * Returns a JSON representation of an instance
+   * @return {Object} JSON
+   */
+  toJSON: function() {
+    // delegate, not alias
+    return this.toObject();
+  }
+});
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Brightness filter class
+   * @class fabric.Image.filters.Brightness
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Brightness({
+   *   brightness: 200
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Brightness',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Brightness.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.brightness=0] Value to brighten the image up (-255..255)
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.brightness = options.brightness || 0;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          brightness = this.brightness;
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+        data[i] += brightness;
+        data[i + 1] += brightness;
+        data[i + 2] += brightness;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        brightness: this.brightness
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness
+   */
+  fabric.Image.filters.Brightness.fromObject = function(object) {
+    return new fabric.Image.filters.Brightness(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Adapted from <a href="http://www.html5rocks.com/en/tutorials/canvas/imagefilters/">html5rocks article</a>
+   * @class fabric.Image.filters.Convolute
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example <caption>Sharpen filter</caption>
+   * var filter = new fabric.Image.filters.Convolute({
+   *   matrix: [ 0, -1,  0,
+   *            -1,  5, -1,
+   *             0, -1,  0 ]
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   * @example <caption>Blur filter</caption>
+   * var filter = new fabric.Image.filters.Convolute({
+   *   matrix: [ 1/9, 1/9, 1/9,
+   *             1/9, 1/9, 1/9,
+   *             1/9, 1/9, 1/9 ]
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   * @example <caption>Emboss filter</caption>
+   * var filter = new fabric.Image.filters.Convolute({
+   *   matrix: [ 1,   1,  1,
+   *             1, 0.7, -1,
+   *            -1,  -1, -1 ]
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   * @example <caption>Emboss filter with opaqueness</caption>
+   * var filter = new fabric.Image.filters.Convolute({
+   *   opaque: true,
+   *   matrix: [ 1,   1,  1,
+   *             1, 0.7, -1,
+   *            -1,  -1, -1 ]
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Convolute',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Convolute.prototype
+     * @param {Object} [options] Options object
+     * @param {Boolean} [options.opaque=false] Opaque value (true/false)
+     * @param {Array} [options.matrix] Filter matrix
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.opaque = options.opaque;
+      this.matrix = options.matrix || [
+        0, 0, 0,
+        0, 1, 0,
+        0, 0, 0
+      ];
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+
+      var weights = this.matrix,
+          context = canvasEl.getContext('2d'),
+          pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+
+          side = Math.round(Math.sqrt(weights.length)),
+          halfSide = Math.floor(side / 2),
+          src = pixels.data,
+          sw = pixels.width,
+          sh = pixels.height,
+          output = context.createImageData(sw, sh),
+          dst = output.data,
+          // go through the destination image pixels
+          alphaFac = this.opaque ? 1 : 0,
+          r, g, b, a, dstOff,
+          scx, scy, srcOff, wt;
+
+      for (var y = 0; y < sh; y++) {
+        for (var x = 0; x < sw; x++) {
+          dstOff = (y * sw + x) * 4;
+          // calculate the weighed sum of the source image pixels that
+          // fall under the convolution matrix
+          r = 0; g = 0; b = 0; a = 0;
+
+          for (var cy = 0; cy < side; cy++) {
+            for (var cx = 0; cx < side; cx++) {
+              scy = y + cy - halfSide;
+              scx = x + cx - halfSide;
+
+              // eslint-disable-next-line max-depth
+              if (scy < 0 || scy > sh || scx < 0 || scx > sw) {
+                continue;
+              }
+
+              srcOff = (scy * sw + scx) * 4;
+              wt = weights[cy * side + cx];
+
+              r += src[srcOff] * wt;
+              g += src[srcOff + 1] * wt;
+              b += src[srcOff + 2] * wt;
+              a += src[srcOff + 3] * wt;
+            }
+          }
+          dst[dstOff] = r;
+          dst[dstOff + 1] = g;
+          dst[dstOff + 2] = b;
+          dst[dstOff + 3] = a + alphaFac * (255 - a);
+        }
+      }
+
+      context.putImageData(output, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        opaque: this.opaque,
+        matrix: this.matrix
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute
+   */
+  fabric.Image.filters.Convolute.fromObject = function(object) {
+    return new fabric.Image.filters.Convolute(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * GradientTransparency filter class
+   * @class fabric.Image.filters.GradientTransparency
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.GradientTransparency#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.GradientTransparency({
+   *   threshold: 200
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+   // eslint-disable-next-line max-len
+  filters.GradientTransparency = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'GradientTransparency',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.GradientTransparency.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.threshold=100] Threshold value
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.threshold = options.threshold || 100;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          threshold = this.threshold,
+          total = data.length;
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+        data[i + 3] = threshold + 255 * (total - i) / total;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        threshold: this.threshold
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.GradientTransparency} Instance of fabric.Image.filters.GradientTransparency
+   */
+  fabric.Image.filters.GradientTransparency.fromObject = function(object) {
+    return new fabric.Image.filters.GradientTransparency(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Grayscale image filter class
+   * @class fabric.Image.filters.Grayscale
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Grayscale();
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Grayscale',
+
+    /**
+     * Applies filter to canvas element
+     * @memberOf fabric.Image.filters.Grayscale.prototype
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          len = imageData.width * imageData.height * 4,
+          index = 0,
+          average;
+
+      while (index < len) {
+        average = (data[index] + data[index + 1] + data[index + 2]) / 3;
+        data[index]     = average;
+        data[index + 1] = average;
+        data[index + 2] = average;
+        index += 4;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale
+   */
+  fabric.Image.filters.Grayscale.fromObject = function() {
+    return new fabric.Image.filters.Grayscale();
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Invert filter class
+   * @class fabric.Image.filters.Invert
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Invert();
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Invert',
+
+    /**
+     * Applies filter to canvas element
+     * @memberOf fabric.Image.filters.Invert.prototype
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = data.length, i;
+
+      for (i = 0; i < iLen; i += 4) {
+        data[i] = 255 - data[i];
+        data[i + 1] = 255 - data[i + 1];
+        data[i + 2] = 255 - data[i + 2];
+      }
+
+      context.putImageData(imageData, 0, 0);
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert
+   */
+  fabric.Image.filters.Invert.fromObject = function() {
+    return new fabric.Image.filters.Invert();
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Mask filter class
+   * See http://resources.aleph-1.com/mask/
+   * @class fabric.Image.filters.Mask
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Mask#initialize} for constructor definition
+   */
+  filters.Mask = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Mask',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Mask.prototype
+     * @param {Object} [options] Options object
+     * @param {fabric.Image} [options.mask] Mask image object
+     * @param {Number} [options.channel=0] Rgb channel (0, 1, 2 or 3)
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.mask = options.mask;
+      this.channel = [0, 1, 2, 3].indexOf(options.channel) > -1 ? options.channel : 0;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      if (!this.mask) {
+        return;
+      }
+
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          maskEl = this.mask.getElement(),
+          maskCanvasEl = fabric.util.createCanvasElement(),
+          channel = this.channel,
+          i,
+          iLen = imageData.width * imageData.height * 4;
+
+      maskCanvasEl.width = canvasEl.width;
+      maskCanvasEl.height = canvasEl.height;
+
+      maskCanvasEl.getContext('2d').drawImage(maskEl, 0, 0, canvasEl.width, canvasEl.height);
+
+      var maskImageData = maskCanvasEl.getContext('2d').getImageData(0, 0, canvasEl.width, canvasEl.height),
+          maskData = maskImageData.data;
+
+      for (i = 0; i < iLen; i += 4) {
+        data[i + 3] = maskData[i + channel];
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        mask: this.mask.toObject(),
+        channel: this.channel
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when a mask filter instance is created
+   */
+  fabric.Image.filters.Mask.fromObject = function(object, callback) {
+    fabric.util.loadImage(object.mask.src, function(img) {
+      object.mask = new fabric.Image(img, object.mask);
+      callback && callback(new fabric.Image.filters.Mask(object));
+    });
+  };
+
+  /**
+   * Indicates that instances of this type are async
+   * @static
+   * @type Boolean
+   * @default
+   */
+  fabric.Image.filters.Mask.async = true;
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Noise filter class
+   * @class fabric.Image.filters.Noise
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Noise({
+   *   noise: 700
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Noise',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Noise.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.noise=0] Noise value
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.noise = options.noise || 0;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          noise = this.noise, rand;
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+
+        rand = (0.5 - Math.random()) * noise;
+
+        data[i] += rand;
+        data[i + 1] += rand;
+        data[i + 2] += rand;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        noise: this.noise
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise
+   */
+  fabric.Image.filters.Noise.fromObject = function(object) {
+    return new fabric.Image.filters.Noise(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Pixelate filter class
+   * @class fabric.Image.filters.Pixelate
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Pixelate({
+   *   blocksize: 8
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Pixelate',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Pixelate.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.blocksize=4] Blocksize for pixelate
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.blocksize = options.blocksize || 4;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = imageData.height,
+          jLen = imageData.width,
+          index, i, j, r, g, b, a;
+
+      for (i = 0; i < iLen; i += this.blocksize) {
+        for (j = 0; j < jLen; j += this.blocksize) {
+
+          index = (i * 4) * jLen + (j * 4);
+
+          r = data[index];
+          g = data[index + 1];
+          b = data[index + 2];
+          a = data[index + 3];
+
+          /*
+           blocksize: 4
+
+           [1,x,x,x,1]
+           [x,x,x,x,1]
+           [x,x,x,x,1]
+           [x,x,x,x,1]
+           [1,1,1,1,1]
+           */
+
+          for (var _i = i, _ilen = i + this.blocksize; _i < _ilen; _i++) {
+            for (var _j = j, _jlen = j + this.blocksize; _j < _jlen; _j++) {
+              index = (_i * 4) * jLen + (_j * 4);
+              data[index] = r;
+              data[index + 1] = g;
+              data[index + 2] = b;
+              data[index + 3] = a;
+            }
+          }
+        }
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        blocksize: this.blocksize
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate
+   */
+  fabric.Image.filters.Pixelate.fromObject = function(object) {
+    return new fabric.Image.filters.Pixelate(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Remove white filter class
+   * @class fabric.Image.filters.RemoveWhite
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.RemoveWhite#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.RemoveWhite({
+   *   threshold: 40,
+   *   distance: 140
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.RemoveWhite = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'RemoveWhite',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.RemoveWhite.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.threshold=30] Threshold value
+     * @param {Number} [options.distance=20] Distance value
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.threshold = options.threshold || 30;
+      this.distance = options.distance || 20;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          threshold = this.threshold,
+          distance = this.distance,
+          limit = 255 - threshold,
+          abs = Math.abs,
+          r, g, b;
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+        r = data[i];
+        g = data[i + 1];
+        b = data[i + 2];
+
+        if (r > limit &&
+            g > limit &&
+            b > limit &&
+            abs(r - g) < distance &&
+            abs(r - b) < distance &&
+            abs(g - b) < distance
+        ) {
+          data[i + 3] = 0;
+        }
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        threshold: this.threshold,
+        distance: this.distance
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.RemoveWhite} Instance of fabric.Image.filters.RemoveWhite
+   */
+  fabric.Image.filters.RemoveWhite.fromObject = function(object) {
+    return new fabric.Image.filters.RemoveWhite(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Sepia filter class
+   * @class fabric.Image.filters.Sepia
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Sepia();
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Sepia = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Sepia',
+
+    /**
+     * Applies filter to canvas element
+     * @memberOf fabric.Image.filters.Sepia.prototype
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = data.length, i, avg;
+
+      for (i = 0; i < iLen; i += 4) {
+        avg = 0.3  * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];
+        data[i] = avg + 100;
+        data[i + 1] = avg + 50;
+        data[i + 2] = avg + 255;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @return {fabric.Image.filters.Sepia} Instance of fabric.Image.filters.Sepia
+   */
+  fabric.Image.filters.Sepia.fromObject = function() {
+    return new fabric.Image.filters.Sepia();
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Sepia2 filter class
+   * @class fabric.Image.filters.Sepia2
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Sepia2();
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Sepia2 = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Sepia2',
+
+    /**
+     * Applies filter to canvas element
+     * @memberOf fabric.Image.filters.Sepia.prototype
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = data.length, i, r, g, b;
+
+      for (i = 0; i < iLen; i += 4) {
+        r = data[i];
+        g = data[i + 1];
+        b = data[i + 2];
+
+        data[i] = (r * 0.393 + g * 0.769 + b * 0.189 ) / 1.351;
+        data[i + 1] = (r * 0.349 + g * 0.686 + b * 0.168 ) / 1.203;
+        data[i + 2] = (r * 0.272 + g * 0.534 + b * 0.131 ) / 2.140;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @return {fabric.Image.filters.Sepia2} Instance of fabric.Image.filters.Sepia2
+   */
+  fabric.Image.filters.Sepia2.fromObject = function() {
+    return new fabric.Image.filters.Sepia2();
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Tint filter class
+   * Adapted from <a href="https://github.com/mezzoblue/PaintbrushJS">https://github.com/mezzoblue/PaintbrushJS</a>
+   * @class fabric.Image.filters.Tint
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Tint#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example <caption>Tint filter with hex color and opacity</caption>
+   * var filter = new fabric.Image.filters.Tint({
+   *   color: '#3513B0',
+   *   opacity: 0.5
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   * @example <caption>Tint filter with rgba color</caption>
+   * var filter = new fabric.Image.filters.Tint({
+   *   color: 'rgba(53, 21, 176, 0.5)'
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Tint = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Tint',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Tint.prototype
+     * @param {Object} [options] Options object
+     * @param {String} [options.color=#000000] Color to tint the image with
+     * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.color = options.color || '#000000';
+      this.opacity = typeof options.opacity !== 'undefined'
+                      ? options.opacity
+                      : new fabric.Color(this.color).getAlpha();
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = data.length, i,
+          tintR, tintG, tintB,
+          r, g, b, alpha1,
+          source;
+
+      source = new fabric.Color(this.color).getSource();
+
+      tintR = source[0] * this.opacity;
+      tintG = source[1] * this.opacity;
+      tintB = source[2] * this.opacity;
+
+      alpha1 = 1 - this.opacity;
+
+      for (i = 0; i < iLen; i += 4) {
+        r = data[i];
+        g = data[i + 1];
+        b = data[i + 2];
+
+        // alpha compositing
+        data[i] = tintR + r * alpha1;
+        data[i + 1] = tintG + g * alpha1;
+        data[i + 2] = tintB + b * alpha1;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        color: this.color,
+        opacity: this.opacity
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Tint} Instance of fabric.Image.filters.Tint
+   */
+  fabric.Image.filters.Tint.fromObject = function(object) {
+    return new fabric.Image.filters.Tint(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Multiply filter class
+   * Adapted from <a href="http://www.laurenscorijn.com/articles/colormath-basics">http://www.laurenscorijn.com/articles/colormath-basics</a>
+   * @class fabric.Image.filters.Multiply
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @example <caption>Multiply filter with hex color</caption>
+   * var filter = new fabric.Image.filters.Multiply({
+   *   color: '#F0F'
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   * @example <caption>Multiply filter with rgb color</caption>
+   * var filter = new fabric.Image.filters.Multiply({
+   *   color: 'rgb(53, 21, 176)'
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Multiply = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Multiply',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Multiply.prototype
+     * @param {Object} [options] Options object
+     * @param {String} [options.color=#000000] Color to multiply the image pixels with
+     */
+    initialize: function(options) {
+      options = options || { };
+
+      this.color = options.color || '#000000';
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          iLen = data.length, i,
+          source;
+
+      source = new fabric.Color(this.color).getSource();
+
+      for (i = 0; i < iLen; i += 4) {
+        data[i] *= source[0] / 255;
+        data[i + 1] *= source[1] / 255;
+        data[i + 2] *= source[2] / 255;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        color: this.color
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Multiply} Instance of fabric.Image.filters.Multiply
+   */
+  fabric.Image.filters.Multiply.fromObject = function(object) {
+    return new fabric.Image.filters.Multiply(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+  'use strict';
+
+  var fabric = global.fabric,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Color Blend filter class
+   * @class fabric.Image.filter.Blend
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @example
+   * var filter = new fabric.Image.filters.Blend({
+   *  color: '#000',
+   *  mode: 'multiply'
+   * });
+   *
+   * var filter = new fabric.Image.filters.Blend({
+   *  image: fabricImageObject,
+   *  mode: 'multiply',
+   *  alpha: 0.5
+   * });
+
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+
+  filters.Blend = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ {
+    type: 'Blend',
+
+    initialize: function(options) {
+      options = options || {};
+      this.color = options.color || '#000';
+      this.image = options.image || false;
+      this.mode = options.mode || 'multiply';
+      this.alpha = options.alpha || 1;
+    },
+
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          tr, tg, tb,
+          r, g, b,
+          _r, _g, _b,
+          source,
+          isImage = false;
+
+      if (this.image) {
+        // Blend images
+        isImage = true;
+
+        var _el = fabric.util.createCanvasElement();
+        _el.width = this.image.width;
+        _el.height = this.image.height;
+
+        var tmpCanvas = new fabric.StaticCanvas(_el);
+        tmpCanvas.add(this.image);
+        var context2 =  tmpCanvas.getContext('2d');
+        source = context2.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data;
+      }
+      else {
+        // Blend color
+        source = new fabric.Color(this.color).getSource();
+
+        tr = source[0] * this.alpha;
+        tg = source[1] * this.alpha;
+        tb = source[2] * this.alpha;
+      }
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+
+        r = data[i];
+        g = data[i + 1];
+        b = data[i + 2];
+
+        if (isImage) {
+          tr = source[i] * this.alpha;
+          tg = source[i + 1] * this.alpha;
+          tb = source[i + 2] * this.alpha;
+        }
+
+        switch (this.mode) {
+          case 'multiply':
+            data[i] = r * tr / 255;
+            data[i + 1] = g * tg / 255;
+            data[i + 2] = b * tb / 255;
+            break;
+          case 'screen':
+            data[i] = 1 - (1 - r) * (1 - tr);
+            data[i + 1] = 1 - (1 - g) * (1 - tg);
+            data[i + 2] = 1 - (1 - b) * (1 - tb);
+            break;
+          case 'add':
+            data[i] = Math.min(255, r + tr);
+            data[i + 1] = Math.min(255, g + tg);
+            data[i + 2] = Math.min(255, b + tb);
+            break;
+          case 'diff':
+          case 'difference':
+            data[i] = Math.abs(r - tr);
+            data[i + 1] = Math.abs(g - tg);
+            data[i + 2] = Math.abs(b - tb);
+            break;
+          case 'subtract':
+            _r = r - tr;
+            _g = g - tg;
+            _b = b - tb;
+
+            data[i] = (_r < 0) ? 0 : _r;
+            data[i + 1] = (_g < 0) ? 0 : _g;
+            data[i + 2] = (_b < 0) ? 0 : _b;
+            break;
+          case 'darken':
+            data[i] = Math.min(r, tr);
+            data[i + 1] = Math.min(g, tg);
+            data[i + 2] = Math.min(b, tb);
+            break;
+          case 'lighten':
+            data[i] = Math.max(r, tr);
+            data[i + 1] = Math.max(g, tg);
+            data[i + 2] = Math.max(b, tb);
+            break;
+        }
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return {
+        color: this.color,
+        image: this.image,
+        mode: this.mode,
+        alpha: this.alpha
+      };
+    }
+  });
+
+  fabric.Image.filters.Blend.fromObject = function(object) {
+    return new fabric.Image.filters.Blend(object);
+  };
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }), pow = Math.pow, floor = Math.floor,
+      sqrt = Math.sqrt, abs = Math.abs, max = Math.max, round = Math.round, sin = Math.sin,
+      ceil = Math.ceil,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Resize image filter class
+   * @class fabric.Image.filters.Resize
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Resize();
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Resize',
+
+    /**
+     * Resize type
+     * @param {String} resizeType
+     * @default
+     */
+    resizeType: 'hermite',
+
+    /**
+     * Scale factor for resizing, x axis
+     * @param {Number} scaleX
+     * @default
+     */
+    scaleX: 0,
+
+    /**
+     * Scale factor for resizing, y axis
+     * @param {Number} scaleY
+     * @default
+     */
+    scaleY: 0,
+
+    /**
+     * LanczosLobes parameter for lanczos filter
+     * @param {Number} lanczosLobes
+     * @default
+     */
+    lanczosLobes: 3,
+
+    /**
+     * Applies filter to canvas element
+     * @memberOf fabric.Image.filters.Resize.prototype
+     * @param {Object} canvasEl Canvas element to apply filter to
+     * @param {Number} scaleX
+     * @param {Number} scaleY
+     */
+    applyTo: function(canvasEl, scaleX, scaleY) {
+      if (scaleX === 1 && scaleY === 1) {
+        return;
+      }
+
+      this.rcpScaleX = 1 / scaleX;
+      this.rcpScaleY = 1 / scaleY;
+
+      var oW = canvasEl.width, oH = canvasEl.height,
+          dW = round(oW * scaleX), dH = round(oH * scaleY),
+          imageData;
+
+      if (this.resizeType === 'sliceHack') {
+        imageData = this.sliceByTwo(canvasEl, oW, oH, dW, dH);
+      }
+      if (this.resizeType === 'hermite') {
+        imageData = this.hermiteFastResize(canvasEl, oW, oH, dW, dH);
+      }
+      if (this.resizeType === 'bilinear') {
+        imageData = this.bilinearFiltering(canvasEl, oW, oH, dW, dH);
+      }
+      if (this.resizeType === 'lanczos') {
+        imageData = this.lanczosResize(canvasEl, oW, oH, dW, dH);
+      }
+      canvasEl.width = dW;
+      canvasEl.height = dH;
+      canvasEl.getContext('2d').putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Filter sliceByTwo
+     * @param {Object} canvasEl Canvas element to apply filter to
+     * @param {Number} oW Original Width
+     * @param {Number} oH Original Height
+     * @param {Number} dW Destination Width
+     * @param {Number} dH Destination Height
+     * @returns {ImageData}
+     */
+    sliceByTwo: function(canvasEl, oW, oH, dW, dH) {
+      var context = canvasEl.getContext('2d'), imageData,
+          multW = 0.5, multH = 0.5, signW = 1, signH = 1,
+          doneW = false, doneH = false, stepW = oW, stepH = oH,
+          tmpCanvas = fabric.util.createCanvasElement(),
+          tmpCtx = tmpCanvas.getContext('2d');
+      dW = floor(dW);
+      dH = floor(dH);
+      tmpCanvas.width = max(dW, oW);
+      tmpCanvas.height = max(dH, oH);
+
+      if (dW > oW) {
+        multW = 2;
+        signW = -1;
+      }
+      if (dH > oH) {
+        multH = 2;
+        signH = -1;
+      }
+      imageData = context.getImageData(0, 0, oW, oH);
+      canvasEl.width = max(dW, oW);
+      canvasEl.height = max(dH, oH);
+      context.putImageData(imageData, 0, 0);
+
+      while (!doneW || !doneH) {
+        oW = stepW;
+        oH = stepH;
+        if (dW * signW < floor(stepW * multW * signW)) {
+          stepW = floor(stepW * multW);
+        }
+        else {
+          stepW = dW;
+          doneW = true;
+        }
+        if (dH * signH < floor(stepH * multH * signH)) {
+          stepH = floor(stepH * multH);
+        }
+        else {
+          stepH = dH;
+          doneH = true;
+        }
+        imageData = context.getImageData(0, 0, oW, oH);
+        tmpCtx.putImageData(imageData, 0, 0);
+        context.clearRect(0, 0, stepW, stepH);
+        context.drawImage(tmpCanvas, 0, 0, oW, oH, 0, 0, stepW, stepH);
+      }
+      return context.getImageData(0, 0, dW, dH);
+    },
+
+    /**
+     * Filter lanczosResize
+     * @param {Object} canvasEl Canvas element to apply filter to
+     * @param {Number} oW Original Width
+     * @param {Number} oH Original Height
+     * @param {Number} dW Destination Width
+     * @param {Number} dH Destination Height
+     * @returns {ImageData}
+     */
+    lanczosResize: function(canvasEl, oW, oH, dW, dH) {
+
+      function lanczosCreate(lobes) {
+        return function(x) {
+          if (x > lobes) {
+            return 0;
+          }
+          x *= Math.PI;
+          if (abs(x) < 1e-16) {
+            return 1;
+          }
+          var xx = x / lobes;
+          return sin(x) * sin(xx) / x / xx;
+        };
+      }
+
+      function process(u) {
+        var v, i, weight, idx, a, red, green,
+            blue, alpha, fX, fY;
+        center.x = (u + 0.5) * ratioX;
+        icenter.x = floor(center.x);
+        for (v = 0; v < dH; v++) {
+          center.y = (v + 0.5) * ratioY;
+          icenter.y = floor(center.y);
+          a = 0; red = 0; green = 0; blue = 0; alpha = 0;
+          for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) {
+            if (i < 0 || i >= oW) {
+              continue;
+            }
+            fX = floor(1000 * abs(i - center.x));
+            if (!cacheLanc[fX]) {
+              cacheLanc[fX] = { };
+            }
+            for (var j = icenter.y - range2Y; j <= icenter.y + range2Y; j++) {
+              if (j < 0 || j >= oH) {
+                continue;
+              }
+              fY = floor(1000 * abs(j - center.y));
+              if (!cacheLanc[fX][fY]) {
+                cacheLanc[fX][fY] = lanczos(sqrt(pow(fX * rcpRatioX, 2) + pow(fY * rcpRatioY, 2)) / 1000);
+              }
+              weight = cacheLanc[fX][fY];
+              if (weight > 0) {
+                idx = (j * oW + i) * 4;
+                a += weight;
+                red += weight * srcData[idx];
+                green += weight * srcData[idx + 1];
+                blue += weight * srcData[idx + 2];
+                alpha += weight * srcData[idx + 3];
+              }
+            }
+          }
+          idx = (v * dW + u) * 4;
+          destData[idx] = red / a;
+          destData[idx + 1] = green / a;
+          destData[idx + 2] = blue / a;
+          destData[idx + 3] = alpha / a;
+        }
+
+        if (++u < dW) {
+          return process(u);
+        }
+        else {
+          return destImg;
+        }
+      }
+
+      var context = canvasEl.getContext('2d'),
+          srcImg = context.getImageData(0, 0, oW, oH),
+          destImg = context.getImageData(0, 0, dW, dH),
+          srcData = srcImg.data, destData = destImg.data,
+          lanczos = lanczosCreate(this.lanczosLobes),
+          ratioX = this.rcpScaleX, ratioY = this.rcpScaleY,
+          rcpRatioX = 2 / this.rcpScaleX, rcpRatioY = 2 / this.rcpScaleY,
+          range2X = ceil(ratioX * this.lanczosLobes / 2),
+          range2Y = ceil(ratioY * this.lanczosLobes / 2),
+          cacheLanc = { }, center = { }, icenter = { };
+
+      return process(0);
+    },
+
+    /**
+     * bilinearFiltering
+     * @param {Object} canvasEl Canvas element to apply filter to
+     * @param {Number} oW Original Width
+     * @param {Number} oH Original Height
+     * @param {Number} dW Destination Width
+     * @param {Number} dH Destination Height
+     * @returns {ImageData}
+     */
+    bilinearFiltering: function(canvasEl, oW, oH, dW, dH) {
+      var a, b, c, d, x, y, i, j, xDiff, yDiff, chnl,
+          color, offset = 0, origPix, ratioX = this.rcpScaleX,
+          ratioY = this.rcpScaleY, context = canvasEl.getContext('2d'),
+          w4 = 4 * (oW - 1), img = context.getImageData(0, 0, oW, oH),
+          pixels = img.data, destImage = context.getImageData(0, 0, dW, dH),
+          destPixels = destImage.data;
+      for (i = 0; i < dH; i++) {
+        for (j = 0; j < dW; j++) {
+          x = floor(ratioX * j);
+          y = floor(ratioY * i);
+          xDiff = ratioX * j - x;
+          yDiff = ratioY * i - y;
+          origPix = 4 * (y * oW + x);
+
+          for (chnl = 0; chnl < 4; chnl++) {
+            a = pixels[origPix + chnl];
+            b = pixels[origPix + 4 + chnl];
+            c = pixels[origPix + w4 + chnl];
+            d = pixels[origPix + w4 + 4 + chnl];
+            color = a * (1 - xDiff) * (1 - yDiff) + b * xDiff * (1 - yDiff) +
+                    c * yDiff * (1 - xDiff) + d * xDiff * yDiff;
+            destPixels[offset++] = color;
+          }
+        }
+      }
+      return destImage;
+    },
+
+    /**
+     * hermiteFastResize
+     * @param {Object} canvasEl Canvas element to apply filter to
+     * @param {Number} oW Original Width
+     * @param {Number} oH Original Height
+     * @param {Number} dW Destination Width
+     * @param {Number} dH Destination Height
+     * @returns {ImageData}
+     */
+    hermiteFastResize: function(canvasEl, oW, oH, dW, dH) {
+      var ratioW = this.rcpScaleX, ratioH = this.rcpScaleY,
+          ratioWHalf = ceil(ratioW / 2),
+          ratioHHalf = ceil(ratioH / 2),
+          context = canvasEl.getContext('2d'),
+          img = context.getImageData(0, 0, oW, oH), data = img.data,
+          img2 = context.getImageData(0, 0, dW, dH), data2 = img2.data;
+      for (var j = 0; j < dH; j++) {
+        for (var i = 0; i < dW; i++) {
+          var x2 = (i + j * dW) * 4, weight = 0, weights = 0, weightsAlpha = 0,
+              gxR = 0, gxG = 0, gxB = 0, gxA = 0, centerY = (j + 0.5) * ratioH;
+          for (var yy = floor(j * ratioH); yy < (j + 1) * ratioH; yy++) {
+            var dy = abs(centerY - (yy + 0.5)) / ratioHHalf,
+                centerX = (i + 0.5) * ratioW, w0 = dy * dy;
+            for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) {
+              var dx = abs(centerX - (xx + 0.5)) / ratioWHalf,
+                  w = sqrt(w0 + dx * dx);
+              /* eslint-disable max-depth */
+              if (w > 1 && w < -1) {
+                continue;
+              }
+              //hermite filter
+              weight = 2 * w * w * w - 3 * w * w + 1;
+              if (weight > 0) {
+                dx = 4 * (xx + yy * oW);
+                //alpha
+                gxA += weight * data[dx + 3];
+                weightsAlpha += weight;
+                //colors
+                if (data[dx + 3] < 255) {
+                  weight = weight * data[dx + 3] / 250;
+                }
+                gxR += weight * data[dx];
+                gxG += weight * data[dx + 1];
+                gxB += weight * data[dx + 2];
+                weights += weight;
+              }
+              /* eslint-enable max-depth */
+            }
+          }
+          data2[x2] = gxR / weights;
+          data2[x2 + 1] = gxG / weights;
+          data2[x2 + 2] = gxB / weights;
+          data2[x2 + 3] = gxA / weightsAlpha;
+        }
+      }
+      return img2;
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return {
+        type: this.type,
+        scaleX: this.scaleX,
+        scaleY: this.scaleY,
+        resizeType: this.resizeType,
+        lanczosLobes: this.lanczosLobes
+      };
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize
+   */
+  fabric.Image.filters.Resize.fromObject = function(object) {
+    return new fabric.Image.filters.Resize(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Color Matrix filter class
+   * @class fabric.Image.filters.ColorMatrix
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.ColorMatrix#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @see {@Link http://www.webwasp.co.uk/tutorials/219/Color_Matrix_Filter.php}
+   * @see {@Link http://phoboslab.org/log/2013/11/fast-image-filters-with-webgl}
+   * @example <caption>Kodachrome filter</caption>
+   * var filter = new fabric.Image.filters.ColorMatrix({
+   *  matrix: [
+       1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,
+       -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,
+       -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,
+       0, 0, 0, 1, 0
+      ]
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'ColorMatrix',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.ColorMatrix.prototype
+     * @param {Object} [options] Options object
+     * @param {Array} [options.matrix] Color Matrix to modify the image data with
+     */
+    initialize: function( options ) {
+      options || ( options = {} );
+      this.matrix = options.matrix || [
+        1, 0, 0, 0, 0,
+        0, 1, 0, 0, 0,
+        0, 0, 1, 0, 0,
+        0, 0, 0, 1, 0
+      ];
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function( canvasEl ) {
+      var context = canvasEl.getContext( '2d' ),
+          imageData = context.getImageData( 0, 0, canvasEl.width, canvasEl.height ),
+          data = imageData.data,
+          iLen = data.length,
+          i,
+          r,
+          g,
+          b,
+          a,
+          m = this.matrix;
+
+      for ( i = 0; i < iLen; i += 4 ) {
+        r = data[ i ];
+        g = data[ i + 1 ];
+        b = data[ i + 2 ];
+        a = data[ i + 3 ];
+
+        data[ i ] = r * m[ 0 ] + g * m[ 1 ] + b * m[ 2 ] + a * m[ 3 ] + m[ 4 ];
+        data[ i + 1 ] = r * m[ 5 ] + g * m[ 6 ] + b * m[ 7 ] + a * m[ 8 ] + m[ 9 ];
+        data[ i + 2 ] = r * m[ 10 ] + g * m[ 11 ] + b * m[ 12 ] + a * m[ 13 ] + m[ 14 ];
+        data[ i + 3 ] = r * m[ 15 ] + g * m[ 16 ] + b * m[ 17 ] + a * m[ 18 ] + m[ 19 ];
+      }
+
+      context.putImageData( imageData, 0, 0 );
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        type: this.type,
+        matrix: this.matrix
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix
+   */
+  fabric.Image.filters.ColorMatrix.fromObject = function( object ) {
+    return new fabric.Image.filters.ColorMatrix( object );
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Contrast filter class
+   * @class fabric.Image.filters.Contrast
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Contrast#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Contrast({
+   *   contrast: 40
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Contrast = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Contrast.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Contrast',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Contrast.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.contrast=0] Value to contrast the image up (-255...255)
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.contrast = options.contrast || 0;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          contrastF = 259 * (this.contrast + 255) / (255 * (259 - this.contrast));
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+        data[i] = contrastF * (data[i] - 128) + 128;
+        data[i + 1] = contrastF * (data[i + 1] - 128) + 128;
+        data[i + 2] = contrastF * (data[i + 2] - 128) + 128;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        contrast: this.contrast
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast
+   */
+  fabric.Image.filters.Contrast.fromObject = function(object) {
+    return new fabric.Image.filters.Contrast(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric  = global.fabric || (global.fabric = { }),
+      extend = fabric.util.object.extend,
+      filters = fabric.Image.filters,
+      createClass = fabric.util.createClass;
+
+  /**
+   * Saturate filter class
+   * @class fabric.Image.filters.Saturate
+   * @memberOf fabric.Image.filters
+   * @extends fabric.Image.filters.BaseFilter
+   * @see {@link fabric.Image.filters.Saturate#initialize} for constructor definition
+   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
+   * @example
+   * var filter = new fabric.Image.filters.Saturate({
+   *   saturate: 100
+   * });
+   * object.filters.push(filter);
+   * object.applyFilters(canvas.renderAll.bind(canvas));
+   */
+  filters.Saturate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Saturate.prototype */ {
+
+    /**
+     * Filter type
+     * @param {String} type
+     * @default
+     */
+    type: 'Saturate',
+
+    /**
+     * Constructor
+     * @memberOf fabric.Image.filters.Saturate.prototype
+     * @param {Object} [options] Options object
+     * @param {Number} [options.saturate=0] Value to saturate the image (-100...100)
+     */
+    initialize: function(options) {
+      options = options || { };
+      this.saturate = options.saturate || 0;
+    },
+
+    /**
+     * Applies filter to canvas element
+     * @param {Object} canvasEl Canvas element to apply filter to
+     */
+    applyTo: function(canvasEl) {
+      var context = canvasEl.getContext('2d'),
+          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
+          data = imageData.data,
+          max, adjust = -this.saturate * 0.01;
+
+      for (var i = 0, len = data.length; i < len; i += 4) {
+        max = Math.max(data[i], data[i + 1], data[i + 2]);
+        data[i] += max !== data[i] ? (max - data[i]) * adjust : 0;
+        data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * adjust : 0;
+        data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * adjust : 0;
+      }
+
+      context.putImageData(imageData, 0, 0);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function() {
+      return extend(this.callSuper('toObject'), {
+        saturate: this.saturate
+      });
+    }
+  });
+
+  /**
+   * Returns filter instance from an object representation
+   * @static
+   * @param {Object} object Object to create an instance from
+   * @return {fabric.Image.filters.Saturate} Instance of fabric.Image.filters.Saturate
+   */
+  fabric.Image.filters.Saturate.fromObject = function(object) {
+    return new fabric.Image.filters.Saturate(object);
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = { }),
+      clone = fabric.util.object.clone,
+      toFixed = fabric.util.toFixed,
+      NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
+      MIN_TEXT_WIDTH = 2;
+
+  if (fabric.Text) {
+    fabric.warn('fabric.Text is already defined');
+    return;
+  }
+
+  var stateProperties = fabric.Object.prototype.stateProperties.concat();
+  stateProperties.push(
+    'fontFamily',
+    'fontWeight',
+    'fontSize',
+    'text',
+    'textDecoration',
+    'textAlign',
+    'fontStyle',
+    'lineHeight',
+    'textBackgroundColor'
+  );
+
+  /**
+   * Text class
+   * @class fabric.Text
+   * @extends fabric.Object
+   * @return {fabric.Text} thisArg
+   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}
+   * @see {@link fabric.Text#initialize} for constructor definition
+   */
+  fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {
+
+    /**
+     * Properties which when set cause object to change dimensions
+     * @type Object
+     * @private
+     */
+    _dimensionAffectingProps: {
+      fontSize: true,
+      fontWeight: true,
+      fontFamily: true,
+      fontStyle: true,
+      lineHeight: true,
+      text: true,
+      charSpacing: true,
+      textAlign: true,
+      strokeWidth: false,
+    },
+
+    /**
+     * @private
+     */
+    _reNewline: /\r?\n/,
+
+    /**
+     * Use this regular expression to filter for whitespace that is not a new line.
+     * Mostly used when text is 'justify' aligned.
+     * @private
+     */
+    _reSpacesAndTabs: /[ \t\r]+/g,
+
+    /**
+     * Retrieves object's fontSize
+     * @method getFontSize
+     * @memberOf fabric.Text.prototype
+     * @return {String} Font size (in pixels)
+     */
+
+    /**
+     * Sets object's fontSize
+     * Does not update the object .width and .height,
+     * call ._initDimensions() to update the values.
+     * @method setFontSize
+     * @memberOf fabric.Text.prototype
+     * @param {Number} fontSize Font size (in pixels)
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's fontWeight
+     * @method getFontWeight
+     * @memberOf fabric.Text.prototype
+     * @return {(String|Number)} Font weight
+     */
+
+    /**
+     * Sets object's fontWeight
+     * Does not update the object .width and .height,
+     * call ._initDimensions() to update the values.
+     * @method setFontWeight
+     * @memberOf fabric.Text.prototype
+     * @param {(Number|String)} fontWeight Font weight
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's fontFamily
+     * @method getFontFamily
+     * @memberOf fabric.Text.prototype
+     * @return {String} Font family
+     */
+
+    /**
+     * Sets object's fontFamily
+     * Does not update the object .width and .height,
+     * call ._initDimensions() to update the values.
+     * @method setFontFamily
+     * @memberOf fabric.Text.prototype
+     * @param {String} fontFamily Font family
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's text
+     * @method getText
+     * @memberOf fabric.Text.prototype
+     * @return {String} text
+     */
+
+    /**
+     * Sets object's text
+     * Does not update the object .width and .height,
+     * call ._initDimensions() to update the values.
+     * @method setText
+     * @memberOf fabric.Text.prototype
+     * @param {String} text Text
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's textDecoration
+     * @method getTextDecoration
+     * @memberOf fabric.Text.prototype
+     * @return {String} Text decoration
+     */
+
+    /**
+     * Sets object's textDecoration
+     * @method setTextDecoration
+     * @memberOf fabric.Text.prototype
+     * @param {String} textDecoration Text decoration
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's fontStyle
+     * @method getFontStyle
+     * @memberOf fabric.Text.prototype
+     * @return {String} Font style
+     */
+
+    /**
+     * Sets object's fontStyle
+     * Does not update the object .width and .height,
+     * call ._initDimensions() to update the values.
+     * @method setFontStyle
+     * @memberOf fabric.Text.prototype
+     * @param {String} fontStyle Font style
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's lineHeight
+     * @method getLineHeight
+     * @memberOf fabric.Text.prototype
+     * @return {Number} Line height
+     */
+
+    /**
+     * Sets object's lineHeight
+     * @method setLineHeight
+     * @memberOf fabric.Text.prototype
+     * @param {Number} lineHeight Line height
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's textAlign
+     * @method getTextAlign
+     * @memberOf fabric.Text.prototype
+     * @return {String} Text alignment
+     */
+
+    /**
+     * Sets object's textAlign
+     * @method setTextAlign
+     * @memberOf fabric.Text.prototype
+     * @param {String} textAlign Text alignment
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Retrieves object's textBackgroundColor
+     * @method getTextBackgroundColor
+     * @memberOf fabric.Text.prototype
+     * @return {String} Text background color
+     */
+
+    /**
+     * Sets object's textBackgroundColor
+     * @method setTextBackgroundColor
+     * @memberOf fabric.Text.prototype
+     * @param {String} textBackgroundColor Text background color
+     * @return {fabric.Text}
+     * @chainable
+     */
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type:                 'text',
+
+    /**
+     * Font size (in pixels)
+     * @type Number
+     * @default
+     */
+    fontSize:             40,
+
+    /**
+     * Font weight (e.g. bold, normal, 400, 600, 800)
+     * @type {(Number|String)}
+     * @default
+     */
+    fontWeight:           'normal',
+
+    /**
+     * Font family
+     * @type String
+     * @default
+     */
+    fontFamily:           'Times New Roman',
+
+    /**
+     * Text decoration Possible values: "", "underline", "overline" or "line-through".
+     * @type String
+     * @default
+     */
+    textDecoration:       '',
+
+    /**
+     * Text alignment. Possible values: "left", "center", "right" or "justify".
+     * @type String
+     * @default
+     */
+    textAlign:            'left',
+
+    /**
+     * Font style . Possible values: "", "normal", "italic" or "oblique".
+     * @type String
+     * @default
+     */
+    fontStyle:            '',
+
+    /**
+     * Line height
+     * @type Number
+     * @default
+     */
+    lineHeight:           1.16,
+
+    /**
+     * Background color of text lines
+     * @type String
+     * @default
+     */
+    textBackgroundColor:  '',
+
+    /**
+     * List of properties to consider when checking if
+     * state of an object is changed ({@link fabric.Object#hasStateChanged})
+     * as well as for history (undo/redo) purposes
+     * @type Array
+     */
+    stateProperties:      stateProperties,
+
+    /**
+     * When defined, an object is rendered via stroke and this property specifies its color.
+     * <b>Backwards incompatibility note:</b> This property was named "strokeStyle" until v1.1.6
+     * @type String
+     * @default
+     */
+    stroke:               null,
+
+    /**
+     * Shadow object representing shadow of this shape.
+     * <b>Backwards incompatibility note:</b> This property was named "textShadow" (String) until v1.2.11
+     * @type fabric.Shadow
+     * @default
+     */
+    shadow:               null,
+
+    /**
+     * @private
+     */
+    _fontSizeFraction: 0.25,
+
+    /**
+     * Text Line proportion to font Size (in pixels)
+     * @type Number
+     * @default
+     */
+    _fontSizeMult:             1.13,
+
+    /**
+     * additional space between characters
+     * expressed in thousands of em unit
+     * @type Number
+     * @default
+     */
+    charSpacing:             0,
+
+    /**
+     * Constructor
+     * @param {String} text Text string
+     * @param {Object} [options] Options object
+     * @return {fabric.Text} thisArg
+     */
+    initialize: function(text, options) {
+      options = options || { };
+      this.text = text;
+      this.__skipDimension = true;
+      this.setOptions(options);
+      this.__skipDimension = false;
+      this._initDimensions();
+    },
+
+    /**
+     * Initialize text dimensions. Render all text on given context
+     * or on a offscreen canvas to get the text width with measureText.
+     * Updates this.width and this.height with the proper values.
+     * Does not return dimensions.
+     * @param {CanvasRenderingContext2D} [ctx] Context to render on
+     * @private
+     */
+    _initDimensions: function(ctx) {
+      if (this.__skipDimension) {
+        return;
+      }
+      if (!ctx) {
+        ctx = fabric.util.createCanvasElement().getContext('2d');
+        this._setTextStyles(ctx);
+      }
+      this._textLines = this._splitTextIntoLines();
+      this._clearCache();
+      this.width = this._getTextWidth(ctx) || this.cursorWidth || MIN_TEXT_WIDTH;
+      this.height = this._getTextHeight(ctx);
+    },
+
+    /**
+     * Returns string representation of an instance
+     * @return {String} String representation of text object
+     */
+    toString: function() {
+      return '#<fabric.Text (' + this.complexity() +
+        '): { "text": "' + this.text + '", "fontFamily": "' + this.fontFamily + '" }>';
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _render: function(ctx) {
+      this.clipTo && fabric.util.clipContext(this, ctx);
+      this._setOpacity(ctx);
+      this._setShadow(ctx);
+      this._setupCompositeOperation(ctx);
+      this._renderTextBackground(ctx);
+      this._setStrokeStyles(ctx);
+      this._setFillStyles(ctx);
+      this._renderText(ctx);
+      this._renderTextDecoration(ctx);
+      this.clipTo && ctx.restore();
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderText: function(ctx) {
+      this._renderTextFill(ctx);
+      this._renderTextStroke(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _setTextStyles: function(ctx) {
+      ctx.textBaseline = 'alphabetic';
+      ctx.font = this._getFontDeclaration();
+    },
+
+    /**
+     * @private
+     * @return {Number} Height of fabric.Text object
+     */
+    _getTextHeight: function() {
+      return this._getHeightOfSingleLine() + (this._textLines.length - 1) * this._getHeightOfLine();
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @return {Number} Maximum width of fabric.Text object
+     */
+    _getTextWidth: function(ctx) {
+      var maxWidth = this._getLineWidth(ctx, 0);
+
+      for (var i = 1, len = this._textLines.length; i < len; i++) {
+        var currentLineWidth = this._getLineWidth(ctx, i);
+        if (currentLineWidth > maxWidth) {
+          maxWidth = currentLineWidth;
+        }
+      }
+      return maxWidth;
+    },
+
+    /*
+     * Calculate object dimensions from its properties
+     * @override
+     * @private
+     */
+    _getNonTransformedDimensions: function() {
+      return { x: this.width, y: this.height };
+    },
+
+    /**
+     * @private
+     * @param {String} method Method name ("fillText" or "strokeText")
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} chars Chars to render
+     * @param {Number} left Left position of text
+     * @param {Number} top Top position of text
+     */
+    _renderChars: function(method, ctx, chars, left, top) {
+      // remove Text word from method var
+      var shortM = method.slice(0, -4), char, width;
+      if (this[shortM].toLive) {
+        var offsetX = -this.width / 2 + this[shortM].offsetX || 0,
+            offsetY = -this.height / 2 + this[shortM].offsetY || 0;
+        ctx.save();
+        ctx.translate(offsetX, offsetY);
+        left -= offsetX;
+        top -= offsetY;
+      }
+      if (this.charSpacing !== 0) {
+        var additionalSpace = this._getWidthOfCharSpacing();
+        chars = chars.split('');
+        for (var i = 0, len = chars.length; i < len; i++) {
+          char = chars[i];
+          width = ctx.measureText(char).width + additionalSpace;
+          ctx[method](char, left, top);
+          left += width > 0 ? width : 0;
+        }
+      }
+      else {
+        ctx[method](chars, left, top);
+      }
+      this[shortM].toLive && ctx.restore();
+    },
+
+    /**
+     * @private
+     * @param {String} method Method name ("fillText" or "strokeText")
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} line Text to render
+     * @param {Number} left Left position of text
+     * @param {Number} top Top position of text
+     * @param {Number} lineIndex Index of a line in a text
+     */
+    _renderTextLine: function(method, ctx, line, left, top, lineIndex) {
+      // lift the line by quarter of fontSize
+      top -= this.fontSize * this._fontSizeFraction;
+
+      // short-circuit
+      var lineWidth = this._getLineWidth(ctx, lineIndex);
+      if (this.textAlign !== 'justify' || this.width < lineWidth) {
+        this._renderChars(method, ctx, line, left, top, lineIndex);
+        return;
+      }
+
+      // stretch the line
+      var words = line.split(/\s+/),
+          charOffset = 0,
+          wordsWidth = this._getWidthOfWords(ctx, words.join(' '), lineIndex, 0),
+          widthDiff = this.width - wordsWidth,
+          numSpaces = words.length - 1,
+          spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,
+          leftOffset = 0, word;
+
+      for (var i = 0, len = words.length; i < len; i++) {
+        while (line[charOffset] === ' ' && charOffset < line.length) {
+          charOffset++;
+        }
+        word = words[i];
+        this._renderChars(method, ctx, word, left + leftOffset, top, lineIndex, charOffset);
+        leftOffset += this._getWidthOfWords(ctx, word, lineIndex, charOffset) + spaceWidth;
+        charOffset += word.length;
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} word
+     */
+    _getWidthOfWords: function (ctx, word) {
+      var width = ctx.measureText(word).width, charCount, additionalSpace;
+      if (this.charSpacing !== 0) {
+        charCount = word.split('').length;
+        additionalSpace = charCount * this._getWidthOfCharSpacing();
+        width += additionalSpace;
+      }
+      return width > 0 ? width : 0;
+    },
+
+    /**
+     * @private
+     * @return {Number} Left offset
+     */
+    _getLeftOffset: function() {
+      return -this.width / 2;
+    },
+
+    /**
+     * @private
+     * @return {Number} Top offset
+     */
+    _getTopOffset: function() {
+      return -this.height / 2;
+    },
+
+    /**
+     * Returns true because text has no style
+     */
+    isEmptyStyles: function() {
+      return true;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} method Method name ("fillText" or "strokeText")
+     */
+    _renderTextCommon: function(ctx, method) {
+
+      var lineHeights = 0, left = this._getLeftOffset(), top = this._getTopOffset();
+
+      for (var i = 0, len = this._textLines.length; i < len; i++) {
+        var heightOfLine = this._getHeightOfLine(ctx, i),
+            maxHeight = heightOfLine / this.lineHeight,
+            lineWidth = this._getLineWidth(ctx, i),
+            leftOffset = this._getLineLeftOffset(lineWidth);
+        this._renderTextLine(
+          method,
+          ctx,
+          this._textLines[i],
+          left + leftOffset,
+          top + lineHeights + maxHeight,
+          i
+        );
+        lineHeights += heightOfLine;
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextFill: function(ctx) {
+      if (!this.fill && this.isEmptyStyles()) {
+        return;
+      }
+
+      this._renderTextCommon(ctx, 'fillText');
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextStroke: function(ctx) {
+      if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {
+        return;
+      }
+
+      if (this.shadow && !this.shadow.affectStroke) {
+        this._removeShadow(ctx);
+      }
+
+      ctx.save();
+      this._setLineDash(ctx, this.strokedashArray);
+      ctx.beginPath();
+      this._renderTextCommon(ctx, 'strokeText');
+      ctx.closePath();
+      ctx.restore();
+    },
+
+    /**
+     * @private
+     * @return {Number} height of line
+     */
+    _getHeightOfLine: function() {
+      return this._getHeightOfSingleLine() * this.lineHeight;
+    },
+
+    /**
+     * @private
+     * @return {Number} height of line without lineHeight
+     */
+    _getHeightOfSingleLine: function() {
+      return this.fontSize * this._fontSizeMult;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextBackground: function(ctx) {
+      this._renderBackground(ctx);
+      this._renderTextLinesBackground(ctx);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextLinesBackground: function(ctx) {
+      if (!this.textBackgroundColor) {
+        return;
+      }
+      var lineTopOffset = 0, heightOfLine,
+          lineWidth, lineLeftOffset;
+
+      ctx.fillStyle = this.textBackgroundColor;
+      for (var i = 0, len = this._textLines.length; i < len; i++) {
+        heightOfLine = this._getHeightOfLine(ctx, i);
+        lineWidth = this._getLineWidth(ctx, i);
+        if (lineWidth > 0) {
+          lineLeftOffset = this._getLineLeftOffset(lineWidth);
+          ctx.fillRect(
+            this._getLeftOffset() + lineLeftOffset,
+            this._getTopOffset() + lineTopOffset,
+            lineWidth,
+            heightOfLine / this.lineHeight
+          );
+        }
+        lineTopOffset += heightOfLine;
+      }
+      // if there is text background color no
+      // other shadows should be casted
+      this._removeShadow(ctx);
+    },
+
+    /**
+     * @private
+     * @param {Number} lineWidth Width of text line
+     * @return {Number} Line left offset
+     */
+    _getLineLeftOffset: function(lineWidth) {
+      if (this.textAlign === 'center') {
+        return (this.width - lineWidth) / 2;
+      }
+      if (this.textAlign === 'right') {
+        return this.width - lineWidth;
+      }
+      return 0;
+    },
+
+    /**
+     * @private
+     */
+    _clearCache: function() {
+      this.__lineWidths = [];
+      this.__lineHeights = [];
+    },
+
+    /**
+     * @private
+     */
+    _shouldClearCache: function() {
+      var shouldClear = false;
+      if (this._forceClearCache) {
+        this._forceClearCache = false;
+        return true;
+      }
+      for (var prop in this._dimensionAffectingProps) {
+        if (this['__' + prop] !== this[prop]) {
+          this['__' + prop] = this[prop];
+          shouldClear = true;
+        }
+      }
+      return shouldClear;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex line number
+     * @return {Number} Line width
+     */
+    _getLineWidth: function(ctx, lineIndex) {
+      if (this.__lineWidths[lineIndex]) {
+        return this.__lineWidths[lineIndex] === -1 ? this.width : this.__lineWidths[lineIndex];
+      }
+
+      var width, wordCount, line = this._textLines[lineIndex];
+
+      if (line === '') {
+        width = 0;
+      }
+      else {
+        width = this._measureLine(ctx, lineIndex);
+      }
+      this.__lineWidths[lineIndex] = width;
+
+      if (width && this.textAlign === 'justify') {
+        wordCount = line.split(/\s+/);
+        if (wordCount.length > 1) {
+          this.__lineWidths[lineIndex] = -1;
+        }
+      }
+      return width;
+    },
+
+    _getWidthOfCharSpacing: function() {
+      if (this.charSpacing !== 0) {
+        return this.fontSize * this.charSpacing / 1000;
+      }
+      return 0;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex line number
+     * @return {Number} Line width
+     */
+    _measureLine: function(ctx, lineIndex) {
+      var line = this._textLines[lineIndex],
+          width = ctx.measureText(line).width,
+          additionalSpace = 0, charCount, finalWidth;
+      if (this.charSpacing !== 0) {
+        charCount = line.split('').length;
+        additionalSpace = (charCount - 1) * this._getWidthOfCharSpacing();
+      }
+      finalWidth = width + additionalSpace;
+      return finalWidth > 0 ? finalWidth : 0;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextDecoration: function(ctx) {
+      if (!this.textDecoration) {
+        return;
+      }
+      var halfOfVerticalBox = this.height / 2,
+          _this = this, offsets = [];
+
+      /** @ignore */
+      function renderLinesAtOffset(offsets) {
+        var i, lineHeight = 0, len, j, oLen, lineWidth,
+            lineLeftOffset, heightOfLine;
+
+        for (i = 0, len = _this._textLines.length; i < len; i++) {
+
+          lineWidth = _this._getLineWidth(ctx, i);
+          lineLeftOffset = _this._getLineLeftOffset(lineWidth);
+          heightOfLine = _this._getHeightOfLine(ctx, i);
+
+          for (j = 0, oLen = offsets.length; j < oLen; j++) {
+            ctx.fillRect(
+              _this._getLeftOffset() + lineLeftOffset,
+              lineHeight + (_this._fontSizeMult - 1 + offsets[j] ) * _this.fontSize - halfOfVerticalBox,
+              lineWidth,
+              _this.fontSize / 15);
+          }
+          lineHeight += heightOfLine;
+        }
+      }
+
+      if (this.textDecoration.indexOf('underline') > -1) {
+        offsets.push(0.85); // 1 - 3/16
+      }
+      if (this.textDecoration.indexOf('line-through') > -1) {
+        offsets.push(0.43);
+      }
+      if (this.textDecoration.indexOf('overline') > -1) {
+        offsets.push(-0.12);
+      }
+      if (offsets.length > 0) {
+        renderLinesAtOffset(offsets);
+      }
+    },
+
+    /**
+     * return font declaration string for canvas context
+     * @returns {String} font declaration formatted for canvas context.
+     */
+    _getFontDeclaration: function() {
+      return [
+        // node-canvas needs "weight style", while browsers need "style weight"
+        (fabric.isLikelyNode ? this.fontWeight : this.fontStyle),
+        (fabric.isLikelyNode ? this.fontStyle : this.fontWeight),
+        this.fontSize + 'px',
+        (fabric.isLikelyNode ? ('"' + this.fontFamily + '"') : this.fontFamily)
+      ].join(' ');
+    },
+
+    /**
+     * Renders text instance on a specified context
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    render: function(ctx, noTransform) {
+      // do not render if object is not visible
+      if (!this.visible) {
+        return;
+      }
+
+      ctx.save();
+      this._setTextStyles(ctx);
+
+      if (this._shouldClearCache()) {
+        this._initDimensions(ctx);
+      }
+      this.drawSelectionBackground(ctx);
+      if (!noTransform) {
+        this.transform(ctx);
+      }
+      if (this.transformMatrix) {
+        ctx.transform.apply(ctx, this.transformMatrix);
+      }
+      if (this.group && this.group.type === 'path-group') {
+        ctx.translate(this.left, this.top);
+      }
+      this._render(ctx);
+      ctx.restore();
+    },
+
+    /**
+     * Returns the text as an array of lines.
+     * @returns {Array} Lines in the text
+     */
+    _splitTextIntoLines: function() {
+      return this.text.split(this._reNewline);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} Object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      var additionalProperties = [
+        'text',
+        'fontSize',
+        'fontWeight',
+        'fontFamily',
+        'fontStyle',
+        'lineHeight',
+        'textDecoration',
+        'textAlign',
+        'textBackgroundColor',
+        'charSpacing'
+      ].concat(propertiesToInclude);
+      return this.callSuper('toObject', additionalProperties);
+    },
+
+    /* _TO_SVG_START_ */
+    /**
+     * Returns SVG representation of an instance
+     * @param {Function} [reviver] Method for further parsing of svg representation.
+     * @return {String} svg representation of an instance
+     */
+    toSVG: function(reviver) {
+      if (!this.ctx) {
+        this.ctx = fabric.util.createCanvasElement().getContext('2d');
+      }
+      var markup = this._createBaseSVGMarkup(),
+          offsets = this._getSVGLeftTopOffsets(this.ctx),
+          textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
+      this._wrapSVGTextAndBg(markup, textAndBg);
+
+      return reviver ? reviver(markup.join('')) : markup.join('');
+    },
+
+    /**
+     * @private
+     */
+    _getSVGLeftTopOffsets: function(ctx) {
+      var lineTop = this._getHeightOfLine(ctx, 0),
+          textLeft = -this.width / 2,
+          textTop = 0;
+
+      return {
+        textLeft: textLeft + (this.group && this.group.type === 'path-group' ? this.left : 0),
+        textTop: textTop + (this.group && this.group.type === 'path-group' ? -this.top : 0),
+        lineTop: lineTop
+      };
+    },
+
+    /**
+     * @private
+     */
+    _wrapSVGTextAndBg: function(markup, textAndBg) {
+      var noShadow = true, filter = this.getSvgFilter(),
+          style = filter === '' ? '' : ' style="' + filter + '"';
+
+      markup.push(
+        '\t<g ', this.getSvgId(), 'transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '"',
+          style, '>\n',
+          textAndBg.textBgRects.join(''),
+          '\t\t<text ',
+            (this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g, '\'') + '" ' : ''),
+            (this.fontSize ? 'font-size="' + this.fontSize + '" ' : ''),
+            (this.fontStyle ? 'font-style="' + this.fontStyle + '" ' : ''),
+            (this.fontWeight ? 'font-weight="' + this.fontWeight + '" ' : ''),
+            (this.textDecoration ? 'text-decoration="' + this.textDecoration + '" ' : ''),
+            'style="', this.getSvgStyles(noShadow), '" >\n',
+            textAndBg.textSpans.join(''),
+          '\t\t</text>\n',
+        '\t</g>\n'
+      );
+    },
+
+    /**
+     * @private
+     * @param {Number} textTopOffset Text top offset
+     * @param {Number} textLeftOffset Text left offset
+     * @return {Object}
+     */
+    _getSVGTextAndBg: function(textTopOffset, textLeftOffset) {
+      var textSpans = [],
+          textBgRects = [],
+          height = 0;
+      // bounding-box background
+      this._setSVGBg(textBgRects);
+
+      // text and text-background
+      for (var i = 0, len = this._textLines.length; i < len; i++) {
+        if (this.textBackgroundColor) {
+          this._setSVGTextLineBg(textBgRects, i, textLeftOffset, textTopOffset, height);
+        }
+        this._setSVGTextLineText(i, textSpans, height, textLeftOffset, textTopOffset, textBgRects);
+        height += this._getHeightOfLine(this.ctx, i);
+      }
+
+      return {
+        textSpans: textSpans,
+        textBgRects: textBgRects
+      };
+    },
+
+    _setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {
+      var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction)
+        - textTopOffset + height - this.height / 2;
+      if (this.textAlign === 'justify') {
+        // i call from here to do not intefere with IText
+        this._setSVGTextLineJustifed(i, textSpans, yPos, textLeftOffset);
+        return;
+      }
+      textSpans.push(
+        '\t\t\t<tspan x="',
+          toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '" ',
+          'y="',
+          toFixed(yPos, NUM_FRACTION_DIGITS),
+          '" ',
+          // doing this on <tspan> elements since setting opacity
+          // on containing <text> one doesn't work in Illustrator
+          this._getFillAttributes(this.fill), '>',
+          fabric.util.string.escapeXml(this._textLines[i]),
+        '</tspan>\n'
+      );
+    },
+
+    _setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) {
+      var ctx = fabric.util.createCanvasElement().getContext('2d');
+
+      this._setTextStyles(ctx);
+
+      var line = this._textLines[i],
+          words = line.split(/\s+/),
+          wordsWidth = this._getWidthOfWords(ctx, words.join('')),
+          widthDiff = this.width - wordsWidth,
+          numSpaces = words.length - 1,
+          spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,
+          word, attributes = this._getFillAttributes(this.fill),
+          len;
+
+      textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i));
+
+      for (i = 0, len = words.length; i < len; i++) {
+        word = words[i];
+        textSpans.push(
+          '\t\t\t<tspan x="',
+            toFixed(textLeftOffset, NUM_FRACTION_DIGITS), '" ',
+            'y="',
+            toFixed(yPos, NUM_FRACTION_DIGITS),
+            '" ',
+            // doing this on <tspan> elements since setting opacity
+            // on containing <text> one doesn't work in Illustrator
+            attributes, '>',
+            fabric.util.string.escapeXml(word),
+          '</tspan>\n'
+        );
+        textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth;
+      }
+    },
+
+    _setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
+      textBgRects.push(
+        '\t\t<rect ',
+          this._getFillAttributes(this.textBackgroundColor),
+          ' x="',
+          toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS),
+          '" y="',
+          toFixed(height - this.height / 2, NUM_FRACTION_DIGITS),
+          '" width="',
+          toFixed(this._getLineWidth(this.ctx, i), NUM_FRACTION_DIGITS),
+          '" height="',
+          toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, NUM_FRACTION_DIGITS),
+        '"></rect>\n');
+    },
+
+    _setSVGBg: function(textBgRects) {
+      if (this.backgroundColor) {
+        textBgRects.push(
+          '\t\t<rect ',
+            this._getFillAttributes(this.backgroundColor),
+            ' x="',
+            toFixed(-this.width / 2, NUM_FRACTION_DIGITS),
+            '" y="',
+            toFixed(-this.height / 2, NUM_FRACTION_DIGITS),
+            '" width="',
+            toFixed(this.width, NUM_FRACTION_DIGITS),
+            '" height="',
+            toFixed(this.height, NUM_FRACTION_DIGITS),
+          '"></rect>\n');
+      }
+    },
+
+    /**
+     * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values
+     * we work around it by "moving" alpha channel into opacity attribute and setting fill's alpha to 1
+     *
+     * @private
+     * @param {*} value
+     * @return {String}
+     */
+    _getFillAttributes: function(value) {
+      var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';
+      if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {
+        return 'fill="' + value + '"';
+      }
+      return 'opacity="' + fillColor.getAlpha() + '" fill="' + fillColor.setAlpha(1).toRgb() + '"';
+    },
+    /* _TO_SVG_END_ */
+
+    /**
+     * Sets specified property to a specified value
+     * @param {String} key
+     * @param {*} value
+     * @return {fabric.Text} thisArg
+     * @chainable
+     */
+    _set: function(key, value) {
+      this.callSuper('_set', key, value);
+
+      if (key in this._dimensionAffectingProps) {
+        this._initDimensions();
+        this.setCoords();
+      }
+    },
+
+    /**
+     * Returns complexity of an instance
+     * @return {Number} complexity
+     */
+    complexity: function() {
+      return 1;
+    }
+  });
+
+  /* _FROM_SVG_START_ */
+  /**
+   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})
+   * @static
+   * @memberOf fabric.Text
+   * @see: http://www.w3.org/TR/SVG/text.html#TextElement
+   */
+  fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(
+    'x y dx dy font-family font-style font-weight font-size text-decoration text-anchor'.split(' '));
+
+  /**
+   * Default SVG font size
+   * @static
+   * @memberOf fabric.Text
+   */
+  fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;
+
+  /**
+   * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)
+   * @static
+   * @memberOf fabric.Text
+   * @param {SVGElement} element Element to parse
+   * @param {Object} [options] Options object
+   * @return {fabric.Text} Instance of fabric.Text
+   */
+  fabric.Text.fromElement = function(element, options) {
+    if (!element) {
+      return null;
+    }
+
+    var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES);
+    options = fabric.util.object.extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes);
+
+    options.top = options.top || 0;
+    options.left = options.left || 0;
+    if ('dx' in parsedAttributes) {
+      options.left += parsedAttributes.dx;
+    }
+    if ('dy' in parsedAttributes) {
+      options.top += parsedAttributes.dy;
+    }
+    if (!('fontSize' in options)) {
+      options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;
+    }
+
+    if (!options.originX) {
+      options.originX = 'left';
+    }
+
+    var textContent = '';
+
+    // The XML is not properly parsed in IE9 so a workaround to get
+    // textContent is through firstChild.data. Another workaround would be
+    // to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)
+    if (!('textContent' in element)) {
+      if ('firstChild' in element && element.firstChild !== null) {
+        if ('data' in element.firstChild && element.firstChild.data !== null) {
+          textContent = element.firstChild.data;
+        }
+      }
+    }
+    else {
+      textContent = element.textContent;
+    }
+
+    textContent = textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' ');
+
+    var text = new fabric.Text(textContent, options),
+        textHeightScaleFactor = text.getHeight() / text.height,
+        lineHeightDiff = (text.height + text.strokeWidth) * text.lineHeight - text.height,
+        scaledDiff = lineHeightDiff * textHeightScaleFactor,
+        textHeight = text.getHeight() + scaledDiff,
+        offX = 0;
+    /*
+      Adjust positioning:
+        x/y attributes in SVG correspond to the bottom-left corner of text bounding box
+        top/left properties in Fabric correspond to center point of text bounding box
+    */
+    if (text.originX === 'left') {
+      offX = text.getWidth() / 2;
+    }
+    if (text.originX === 'right') {
+      offX = -text.getWidth() / 2;
+    }
+    text.set({
+      left: text.getLeft() + offX,
+      top: text.getTop() - textHeight / 2 + text.fontSize * (0.18 + text._fontSizeFraction) / text.lineHeight /* 0.3 is the old lineHeight */
+    });
+
+    return text;
+  };
+  /* _FROM_SVG_END_ */
+
+  /**
+   * Returns fabric.Text instance from an object representation
+   * @static
+   * @memberOf fabric.Text
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created
+   * @return {fabric.Text} Instance of fabric.Text
+   */
+  fabric.Text.fromObject = function(object, callback) {
+    var text = new fabric.Text(object.text, clone(object));
+    callback && callback(text);
+    return text;
+  };
+
+  fabric.util.createAccessors(fabric.Text);
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function() {
+
+  var clone = fabric.util.object.clone;
+
+  /**
+   * IText class (introduced in <b>v1.4</b>) Events are also fired with "text:"
+   * prefix when observing canvas.
+   * @class fabric.IText
+   * @extends fabric.Text
+   * @mixes fabric.Observable
+   *
+   * @fires changed
+   * @fires selection:changed
+   * @fires editing:entered
+   * @fires editing:exited
+   *
+   * @return {fabric.IText} thisArg
+   * @see {@link fabric.IText#initialize} for constructor definition
+   *
+   * <p>Supported key combinations:</p>
+   * <pre>
+   *   Move cursor:                    left, right, up, down
+   *   Select character:               shift + left, shift + right
+   *   Select text vertically:         shift + up, shift + down
+   *   Move cursor by word:            alt + left, alt + right
+   *   Select words:                   shift + alt + left, shift + alt + right
+   *   Move cursor to line start/end:  cmd + left, cmd + right or home, end
+   *   Select till start/end of line:  cmd + shift + left, cmd + shift + right or shift + home, shift + end
+   *   Jump to start/end of text:      cmd + up, cmd + down
+   *   Select till start/end of text:  cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown
+   *   Delete character:               backspace
+   *   Delete word:                    alt + backspace
+   *   Delete line:                    cmd + backspace
+   *   Forward delete:                 delete
+   *   Copy text:                      ctrl/cmd + c
+   *   Paste text:                     ctrl/cmd + v
+   *   Cut text:                       ctrl/cmd + x
+   *   Select entire text:             ctrl/cmd + a
+   *   Quit editing                    tab or esc
+   * </pre>
+   *
+   * <p>Supported mouse/touch combination</p>
+   * <pre>
+   *   Position cursor:                click/touch
+   *   Create selection:               click/touch & drag
+   *   Create selection:               click & shift + click
+   *   Select word:                    double click
+   *   Select line:                    triple click
+   * </pre>
+   */
+  fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'i-text',
+
+    /**
+     * Index where text selection starts (or where cursor is when there is no selection)
+     * @type Number
+     * @default
+     */
+    selectionStart: 0,
+
+    /**
+     * Index where text selection ends
+     * @type Number
+     * @default
+     */
+    selectionEnd: 0,
+
+    /**
+     * Color of text selection
+     * @type String
+     * @default
+     */
+    selectionColor: 'rgba(17,119,255,0.3)',
+
+    /**
+     * Indicates whether text is in editing mode
+     * @type Boolean
+     * @default
+     */
+    isEditing: false,
+
+    /**
+     * Indicates whether a text can be edited
+     * @type Boolean
+     * @default
+     */
+    editable: true,
+
+    /**
+     * Border color of text object while it's in editing mode
+     * @type String
+     * @default
+     */
+    editingBorderColor: 'rgba(102,153,255,0.25)',
+
+    /**
+     * Width of cursor (in px)
+     * @type Number
+     * @default
+     */
+    cursorWidth: 2,
+
+    /**
+     * Color of default cursor (when not overwritten by character style)
+     * @type String
+     * @default
+     */
+    cursorColor: '#333',
+
+    /**
+     * Delay between cursor blink (in ms)
+     * @type Number
+     * @default
+     */
+    cursorDelay: 1000,
+
+    /**
+     * Duration of cursor fadein (in ms)
+     * @type Number
+     * @default
+     */
+    cursorDuration: 600,
+
+    /**
+     * Object containing character styles
+     * (where top-level properties corresponds to line number and 2nd-level properties -- to char number in a line)
+     * @type Object
+     * @default
+     */
+    styles: null,
+
+    /**
+     * Indicates whether internal text char widths can be cached
+     * @type Boolean
+     * @default
+     */
+    caching: true,
+
+    /**
+     * @private
+     */
+    _reSpace: /\s|\n/,
+
+    /**
+     * @private
+     */
+    _currentCursorOpacity: 0,
+
+    /**
+     * @private
+     */
+    _selectionDirection: null,
+
+    /**
+     * @private
+     */
+    _abortCursorAnimation: false,
+
+    /**
+     * @private
+     */
+    __widthOfSpace: [],
+
+    /**
+     * Constructor
+     * @param {String} text Text string
+     * @param {Object} [options] Options object
+     * @return {fabric.IText} thisArg
+     */
+    initialize: function(text, options) {
+      this.styles = options ? (options.styles || { }) : { };
+      this.callSuper('initialize', text, options);
+      this.initBehavior();
+    },
+
+    /**
+     * @private
+     */
+    _clearCache: function() {
+      this.callSuper('_clearCache');
+      this.__widthOfSpace = [];
+    },
+
+    /**
+     * Returns true if object has no styling
+     */
+    isEmptyStyles: function() {
+      if (!this.styles) {
+        return true;
+      }
+      var obj = this.styles;
+
+      for (var p1 in obj) {
+        for (var p2 in obj[p1]) {
+          // eslint-disable-next-line no-unused-vars
+          for (var p3 in obj[p1][p2]) {
+            return false;
+          }
+        }
+      }
+      return true;
+    },
+
+    /**
+     * Sets selection start (left boundary of a selection)
+     * @param {Number} index Index to set selection start to
+     */
+    setSelectionStart: function(index) {
+      index = Math.max(index, 0);
+      this._updateAndFire('selectionStart', index);
+    },
+
+    /**
+     * Sets selection end (right boundary of a selection)
+     * @param {Number} index Index to set selection end to
+     */
+    setSelectionEnd: function(index) {
+      index = Math.min(index, this.text.length);
+      this._updateAndFire('selectionEnd', index);
+    },
+
+    /**
+     * @private
+     * @param {String} property 'selectionStart' or 'selectionEnd'
+     * @param {Number} index new position of property
+     */
+    _updateAndFire: function(property, index) {
+      if (this[property] !== index) {
+        this._fireSelectionChanged();
+        this[property] = index;
+      }
+      this._updateTextarea();
+    },
+
+    /**
+     * Fires the even of selection changed
+     * @private
+     */
+    _fireSelectionChanged: function() {
+      this.fire('selection:changed');
+      this.canvas && this.canvas.fire('text:selection:changed', { target: this });
+    },
+
+    /**
+     * Gets style of a current selection/cursor (at the start position)
+     * @param {Number} [startIndex] Start index to get styles at
+     * @param {Number} [endIndex] End index to get styles at
+     * @return {Object} styles Style object at a specified (or current) index
+     */
+    getSelectionStyles: function(startIndex, endIndex) {
+
+      if (arguments.length === 2) {
+        var styles = [];
+        for (var i = startIndex; i < endIndex; i++) {
+          styles.push(this.getSelectionStyles(i));
+        }
+        return styles;
+      }
+
+      var loc = this.get2DCursorLocation(startIndex),
+          style = this._getStyleDeclaration(loc.lineIndex, loc.charIndex);
+
+      return style || {};
+    },
+
+    /**
+     * Sets style of a current selection
+     * @param {Object} [styles] Styles object
+     * @return {fabric.IText} thisArg
+     * @chainable
+     */
+    setSelectionStyles: function(styles) {
+      if (this.selectionStart === this.selectionEnd) {
+        this._extendStyles(this.selectionStart, styles);
+      }
+      else {
+        for (var i = this.selectionStart; i < this.selectionEnd; i++) {
+          this._extendStyles(i, styles);
+        }
+      }
+      /* not included in _extendStyles to avoid clearing cache more than once */
+      this._forceClearCache = true;
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _extendStyles: function(index, styles) {
+      var loc = this.get2DCursorLocation(index);
+
+      if (!this._getLineStyle(loc.lineIndex)) {
+        this._setLineStyle(loc.lineIndex, {});
+      }
+
+      if (!this._getStyleDeclaration(loc.lineIndex, loc.charIndex)) {
+        this._setStyleDeclaration(loc.lineIndex, loc.charIndex, {});
+      }
+
+      fabric.util.object.extend(this._getStyleDeclaration(loc.lineIndex, loc.charIndex), styles);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Boolean} noTransform
+     */
+    render: function(ctx, noTransform) {
+      this.clearContextTop();
+      this.callSuper('render', ctx, noTransform);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _render: function(ctx) {
+      this.callSuper('_render', ctx);
+      this.ctx = ctx;
+      // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor
+      // the correct position but not at every cursor animation.
+      this.cursorOffsetCache = { };
+      this.renderCursorOrSelection();
+    },
+
+    /**
+     * Prepare and clean the contextTop
+     */
+    clearContextTop: function() {
+      if (!this.active || !this.isEditing) {
+        return;
+      }
+      if (this.canvas && this.canvas.contextTop) {
+        var ctx = this.canvas.contextTop;
+        ctx.save();
+        ctx.transform.apply(ctx, this.canvas.viewportTransform);
+        this.transform(ctx);
+        this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);
+        this._clearTextArea(ctx);
+        ctx.restore();
+      }
+    },
+
+    /**
+     * Renders cursor or selection (depending on what exists)
+     */
+    renderCursorOrSelection: function() {
+      if (!this.active || !this.isEditing) {
+        return;
+      }
+      var chars = this.text.split(''),
+          boundaries, ctx;
+      if (this.canvas && this.canvas.contextTop) {
+        ctx = this.canvas.contextTop;
+        ctx.save();
+        ctx.transform.apply(ctx, this.canvas.viewportTransform);
+        this.transform(ctx);
+        this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);
+        this._clearTextArea(ctx);
+      }
+      else {
+        ctx = this.ctx;
+        ctx.save();
+      }
+      if (this.selectionStart === this.selectionEnd) {
+        boundaries = this._getCursorBoundaries(chars, 'cursor');
+        this.renderCursor(boundaries, ctx);
+      }
+      else {
+        boundaries = this._getCursorBoundaries(chars, 'selection');
+        this.renderSelection(chars, boundaries, ctx);
+      }
+      ctx.restore();
+    },
+
+    _clearTextArea: function(ctx) {
+      // we add 4 pixel, to be sure to do not leave any pixel out
+      var width = this.width + 4, height = this.height + 4;
+      ctx.clearRect(-width / 2, -height / 2, width, height);
+    },
+    /**
+     * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)
+     * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.
+     */
+    get2DCursorLocation: function(selectionStart) {
+      if (typeof selectionStart === 'undefined') {
+        selectionStart = this.selectionStart;
+      }
+      var len = this._textLines.length;
+      for (var i = 0; i < len; i++) {
+        if (selectionStart <= this._textLines[i].length) {
+          return {
+            lineIndex: i,
+            charIndex: selectionStart
+          };
+        }
+        selectionStart -= this._textLines[i].length + 1;
+      }
+      return {
+        lineIndex: i - 1,
+        charIndex: this._textLines[i - 1].length < selectionStart ? this._textLines[i - 1].length : selectionStart
+      };
+    },
+
+    /**
+     * Returns complete style of char at the current cursor
+     * @param {Number} lineIndex Line index
+     * @param {Number} charIndex Char index
+     * @return {Object} Character style
+     */
+    getCurrentCharStyle: function(lineIndex, charIndex) {
+      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);
+
+      return {
+        fontSize: style && style.fontSize || this.fontSize,
+        fill: style && style.fill || this.fill,
+        textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor,
+        textDecoration: style && style.textDecoration || this.textDecoration,
+        fontFamily: style && style.fontFamily || this.fontFamily,
+        fontWeight: style && style.fontWeight || this.fontWeight,
+        fontStyle: style && style.fontStyle || this.fontStyle,
+        stroke: style && style.stroke || this.stroke,
+        strokeWidth: style && style.strokeWidth || this.strokeWidth
+      };
+    },
+
+    /**
+     * Returns fontSize of char at the current cursor
+     * @param {Number} lineIndex Line index
+     * @param {Number} charIndex Char index
+     * @return {Number} Character font size
+     */
+    getCurrentCharFontSize: function(lineIndex, charIndex) {
+      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);
+      return style && style.fontSize ? style.fontSize : this.fontSize;
+    },
+
+    /**
+     * Returns color (fill) of char at the current cursor
+     * @param {Number} lineIndex Line index
+     * @param {Number} charIndex Char index
+     * @return {String} Character color (fill)
+     */
+    getCurrentCharColor: function(lineIndex, charIndex) {
+      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);
+      return style && style.fill ? style.fill : this.cursorColor;
+    },
+
+    /**
+     * Returns cursor boundaries (left, top, leftOffset, topOffset)
+     * @private
+     * @param {Array} chars Array of characters
+     * @param {String} typeOfBoundaries
+     */
+    _getCursorBoundaries: function(chars, typeOfBoundaries) {
+
+      // left/top are left/top of entire text box
+      // leftOffset/topOffset are offset from that left/top point of a text box
+
+      var left = Math.round(this._getLeftOffset()),
+          top = this._getTopOffset(),
+
+          offsets = this._getCursorBoundariesOffsets(
+                      chars, typeOfBoundaries);
+
+      return {
+        left: left,
+        top: top,
+        leftOffset: offsets.left + offsets.lineLeft,
+        topOffset: offsets.top
+      };
+    },
+
+    /**
+     * @private
+     */
+    _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) {
+      if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {
+        return this.cursorOffsetCache;
+      }
+      var lineLeftOffset = 0,
+          lineIndex = 0,
+          charIndex = 0,
+          topOffset = 0,
+          leftOffset = 0,
+          boundaries;
+
+      for (var i = 0; i < this.selectionStart; i++) {
+        if (chars[i] === '\n') {
+          leftOffset = 0;
+          topOffset += this._getHeightOfLine(this.ctx, lineIndex);
+
+          lineIndex++;
+          charIndex = 0;
+        }
+        else {
+          leftOffset += this._getWidthOfChar(this.ctx, chars[i], lineIndex, charIndex);
+          charIndex++;
+        }
+
+        lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex));
+      }
+      if (typeOfBoundaries === 'cursor') {
+        topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, lineIndex) / this.lineHeight
+          - this.getCurrentCharFontSize(lineIndex, charIndex) * (1 - this._fontSizeFraction);
+      }
+      if (this.charSpacing !== 0 && charIndex === this._textLines[lineIndex].length) {
+        leftOffset -= this._getWidthOfCharSpacing();
+      }
+      boundaries = {
+        top: topOffset,
+        left: leftOffset > 0 ? leftOffset : 0,
+        lineLeft: lineLeftOffset
+      };
+      this.cursorOffsetCache = boundaries;
+      return this.cursorOffsetCache;
+    },
+
+    /**
+     * Renders cursor
+     * @param {Object} boundaries
+     * @param {CanvasRenderingContext2D} ctx transformed context to draw on
+     */
+    renderCursor: function(boundaries, ctx) {
+
+      var cursorLocation = this.get2DCursorLocation(),
+          lineIndex = cursorLocation.lineIndex,
+          charIndex = cursorLocation.charIndex,
+          charHeight = this.getCurrentCharFontSize(lineIndex, charIndex),
+          leftOffset = (lineIndex === 0 && charIndex === 0)
+                    ? this._getLineLeftOffset(this._getLineWidth(ctx, lineIndex))
+                    : boundaries.leftOffset,
+          multiplier = this.scaleX * this.canvas.getZoom(),
+          cursorWidth = this.cursorWidth / multiplier;
+
+      ctx.fillStyle = this.getCurrentCharColor(lineIndex, charIndex);
+      ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity;
+
+      ctx.fillRect(
+        boundaries.left + leftOffset - cursorWidth / 2,
+        boundaries.top + boundaries.topOffset,
+        cursorWidth,
+        charHeight);
+    },
+
+    /**
+     * Renders text selection
+     * @param {Array} chars Array of characters
+     * @param {Object} boundaries Object with left/top/leftOffset/topOffset
+     * @param {CanvasRenderingContext2D} ctx transformed context to draw on
+     */
+    renderSelection: function(chars, boundaries, ctx) {
+
+      ctx.fillStyle = this.selectionColor;
+
+      var start = this.get2DCursorLocation(this.selectionStart),
+          end = this.get2DCursorLocation(this.selectionEnd),
+          startLine = start.lineIndex,
+          endLine = end.lineIndex;
+      for (var i = startLine; i <= endLine; i++) {
+        var lineOffset = this._getLineLeftOffset(this._getLineWidth(ctx, i)) || 0,
+            lineHeight = this._getHeightOfLine(this.ctx, i),
+            realLineHeight = 0, boxWidth = 0, line = this._textLines[i];
+
+        if (i === startLine) {
+          for (var j = 0, len = line.length; j < len; j++) {
+            if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) {
+              boxWidth += this._getWidthOfChar(ctx, line[j], i, j);
+            }
+            if (j < start.charIndex) {
+              lineOffset += this._getWidthOfChar(ctx, line[j], i, j);
+            }
+          }
+          if (j === line.length) {
+            boxWidth -= this._getWidthOfCharSpacing();
+          }
+        }
+        else if (i > startLine && i < endLine) {
+          boxWidth += this._getLineWidth(ctx, i) || 5;
+        }
+        else if (i === endLine) {
+          for (var j2 = 0, j2len = end.charIndex; j2 < j2len; j2++) {
+            boxWidth += this._getWidthOfChar(ctx, line[j2], i, j2);
+          }
+          if (end.charIndex === line.length) {
+            boxWidth -= this._getWidthOfCharSpacing();
+          }
+        }
+        realLineHeight = lineHeight;
+        if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {
+          lineHeight /= this.lineHeight;
+        }
+        ctx.fillRect(
+          boundaries.left + lineOffset,
+          boundaries.top + boundaries.topOffset,
+          boxWidth > 0 ? boxWidth : 0,
+          lineHeight);
+
+        boundaries.topOffset += realLineHeight;
+      }
+    },
+
+    /**
+     * @private
+     * @param {String} method
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} line Content of the line
+     * @param {Number} left
+     * @param {Number} top
+     * @param {Number} lineIndex
+     * @param {Number} charOffset
+     */
+    _renderChars: function(method, ctx, line, left, top, lineIndex, charOffset) {
+
+      if (this.isEmptyStyles()) {
+        return this._renderCharsFast(method, ctx, line, left, top);
+      }
+
+      charOffset = charOffset || 0;
+
+      // set proper line offset
+      var lineHeight = this._getHeightOfLine(ctx, lineIndex),
+          prevStyle,
+          thisStyle,
+          charsToRender = '';
+
+      ctx.save();
+      top -= lineHeight / this.lineHeight * this._fontSizeFraction;
+      for (var i = charOffset, len = line.length + charOffset; i <= len; i++) {
+        prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i);
+        thisStyle = this.getCurrentCharStyle(lineIndex, i + 1);
+
+        if (this._hasStyleChanged(prevStyle, thisStyle) || i === len) {
+          this._renderChar(method, ctx, lineIndex, i - 1, charsToRender, left, top, lineHeight);
+          charsToRender = '';
+          prevStyle = thisStyle;
+        }
+        charsToRender += line[i - charOffset];
+      }
+      ctx.restore();
+    },
+
+    /**
+     * @private
+     * @param {String} method
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} line Content of the line
+     * @param {Number} left Left coordinate
+     * @param {Number} top Top coordinate
+     */
+    _renderCharsFast: function(method, ctx, line, left, top) {
+
+      if (method === 'fillText' && this.fill) {
+        this.callSuper('_renderChars', method, ctx, line, left, top);
+      }
+      if (method === 'strokeText' && ((this.stroke && this.strokeWidth > 0) || this.skipFillStrokeCheck)) {
+        this.callSuper('_renderChars', method, ctx, line, left, top);
+      }
+    },
+
+    /**
+     * @private
+     * @param {String} method
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex
+     * @param {Number} i
+     * @param {String} _char
+     * @param {Number} left Left coordinate
+     * @param {Number} top Top coordinate
+     * @param {Number} lineHeight Height of the line
+     */
+    _renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) {
+      var charWidth, charHeight, shouldFill, shouldStroke,
+          decl = this._getStyleDeclaration(lineIndex, i),
+          offset, textDecoration, chars, additionalSpace, _charWidth;
+
+      if (decl) {
+        charHeight = this._getHeightOfChar(ctx, _char, lineIndex, i);
+        shouldStroke = decl.stroke;
+        shouldFill = decl.fill;
+        textDecoration = decl.textDecoration;
+      }
+      else {
+        charHeight = this.fontSize;
+      }
+
+      shouldStroke = (shouldStroke || this.stroke) && method === 'strokeText';
+      shouldFill = (shouldFill || this.fill) && method === 'fillText';
+
+      decl && ctx.save();
+
+      charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i, decl || null);
+      textDecoration = textDecoration || this.textDecoration;
+
+      if (decl && decl.textBackgroundColor) {
+        this._removeShadow(ctx);
+      }
+      if (this.charSpacing !== 0) {
+        additionalSpace = this._getWidthOfCharSpacing();
+        chars = _char.split('');
+        charWidth = 0;
+        for (var j = 0, len = chars.length, char; j < len; j++) {
+          char = chars[j];
+          shouldFill && ctx.fillText(char, left + charWidth, top);
+          shouldStroke && ctx.strokeText(char, left + charWidth, top);
+          _charWidth = ctx.measureText(char).width + additionalSpace;
+          charWidth += _charWidth > 0 ? _charWidth : 0;
+        }
+      }
+      else {
+        shouldFill && ctx.fillText(_char, left, top);
+        shouldStroke && ctx.strokeText(_char, left, top);
+      }
+
+      if (textDecoration || textDecoration !== '') {
+        offset = this._fontSizeFraction * lineHeight / this.lineHeight;
+        this._renderCharDecoration(ctx, textDecoration, left, top, offset, charWidth, charHeight);
+      }
+
+      decl && ctx.restore();
+      ctx.translate(charWidth, 0);
+    },
+
+    /**
+     * @private
+     * @param {Object} prevStyle
+     * @param {Object} thisStyle
+     */
+    _hasStyleChanged: function(prevStyle, thisStyle) {
+      return (prevStyle.fill !== thisStyle.fill ||
+              prevStyle.fontSize !== thisStyle.fontSize ||
+              prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor ||
+              prevStyle.textDecoration !== thisStyle.textDecoration ||
+              prevStyle.fontFamily !== thisStyle.fontFamily ||
+              prevStyle.fontWeight !== thisStyle.fontWeight ||
+              prevStyle.fontStyle !== thisStyle.fontStyle ||
+              prevStyle.stroke !== thisStyle.stroke ||
+              prevStyle.strokeWidth !== thisStyle.strokeWidth
+      );
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderCharDecoration: function(ctx, textDecoration, left, top, offset, charWidth, charHeight) {
+
+      if (!textDecoration) {
+        return;
+      }
+
+      var decorationWeight = charHeight / 15,
+          positions = {
+            underline: top + charHeight / 10,
+            'line-through': top - charHeight * (this._fontSizeFraction + this._fontSizeMult - 1) + decorationWeight,
+            overline: top - (this._fontSizeMult - this._fontSizeFraction) * charHeight
+          },
+          decorations = ['underline', 'line-through', 'overline'], i, decoration;
+
+      for (i = 0; i < decorations.length; i++) {
+        decoration = decorations[i];
+        if (textDecoration.indexOf(decoration) > -1) {
+          ctx.fillRect(left, positions[decoration], charWidth , decorationWeight);
+        }
+      }
+    },
+
+    /**
+     * @private
+     * @param {String} method
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} line
+     * @param {Number} left
+     * @param {Number} top
+     * @param {Number} lineIndex
+     */
+    _renderTextLine: function(method, ctx, line, left, top, lineIndex) {
+      // to "cancel" this.fontSize subtraction in fabric.Text#_renderTextLine
+      // the adding 0.03 is just to align text with itext by overlap test
+      if (!this.isEmptyStyles()) {
+        top += this.fontSize * (this._fontSizeFraction + 0.03);
+      }
+      this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex);
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextDecoration: function(ctx) {
+      if (this.isEmptyStyles()) {
+        return this.callSuper('_renderTextDecoration', ctx);
+      }
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _renderTextLinesBackground: function(ctx) {
+      this.callSuper('_renderTextLinesBackground', ctx);
+
+      var lineTopOffset = 0, heightOfLine,
+          lineWidth, lineLeftOffset,
+          leftOffset = this._getLeftOffset(),
+          topOffset = this._getTopOffset(),
+          line, _char, style;
+
+      for (var i = 0, len = this._textLines.length; i < len; i++) {
+        heightOfLine = this._getHeightOfLine(ctx, i);
+        line = this._textLines[i];
+
+        if (line === '' || !this.styles || !this._getLineStyle(i)) {
+          lineTopOffset += heightOfLine;
+          continue;
+        }
+
+        lineWidth = this._getLineWidth(ctx, i);
+        lineLeftOffset = this._getLineLeftOffset(lineWidth);
+
+        for (var j = 0, jlen = line.length; j < jlen; j++) {
+          style = this._getStyleDeclaration(i, j);
+          if (!style || !style.textBackgroundColor) {
+            continue;
+          }
+          _char = line[j];
+
+          ctx.fillStyle = style.textBackgroundColor;
+
+          ctx.fillRect(
+            leftOffset + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j),
+            topOffset + lineTopOffset,
+            this._getWidthOfChar(ctx, _char, i, j),
+            heightOfLine / this.lineHeight
+          );
+        }
+        lineTopOffset += heightOfLine;
+      }
+    },
+
+    /**
+     * @private
+     */
+    _getCacheProp: function(_char, styleDeclaration) {
+      return _char +
+             styleDeclaration.fontSize +
+             styleDeclaration.fontWeight +
+             styleDeclaration.fontStyle;
+    },
+
+    /**
+     * @private
+     * @param {String} fontFamily name
+     * @return {Object} reference to cache
+     */
+    _getFontCache: function(fontFamily) {
+      if (!fabric.charWidthsCache[fontFamily]) {
+        fabric.charWidthsCache[fontFamily] = { };
+      }
+      return fabric.charWidthsCache[fontFamily];
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} _char
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @param {Object} [decl]
+     */
+    _applyCharStylesGetWidth: function(ctx, _char, lineIndex, charIndex, decl) {
+      var charDecl = decl || this._getStyleDeclaration(lineIndex, charIndex),
+          styleDeclaration = clone(charDecl),
+          width, cacheProp, charWidthsCache;
+
+      this._applyFontStyles(styleDeclaration);
+      charWidthsCache = this._getFontCache(styleDeclaration.fontFamily);
+      cacheProp = this._getCacheProp(_char, styleDeclaration);
+
+      // short-circuit if no styles for this char
+      // global style from object is always applyed and handled by save and restore
+      if (!charDecl && charWidthsCache[cacheProp] && this.caching) {
+        return charWidthsCache[cacheProp];
+      }
+
+      if (typeof styleDeclaration.shadow === 'string') {
+        styleDeclaration.shadow = new fabric.Shadow(styleDeclaration.shadow);
+      }
+
+      var fill = styleDeclaration.fill || this.fill;
+      ctx.fillStyle = fill.toLive
+        ? fill.toLive(ctx, this)
+        : fill;
+
+      if (styleDeclaration.stroke) {
+        ctx.strokeStyle = (styleDeclaration.stroke && styleDeclaration.stroke.toLive)
+          ? styleDeclaration.stroke.toLive(ctx, this)
+          : styleDeclaration.stroke;
+      }
+
+      ctx.lineWidth = styleDeclaration.strokeWidth || this.strokeWidth;
+      ctx.font = this._getFontDeclaration.call(styleDeclaration);
+
+      //if we want this._setShadow.call to work with styleDeclarion
+      //we have to add those references
+      if (styleDeclaration.shadow) {
+        styleDeclaration.scaleX = this.scaleX;
+        styleDeclaration.scaleY = this.scaleY;
+        styleDeclaration.canvas = this.canvas;
+        styleDeclaration.getObjectScaling = this.getObjectScaling;
+        this._setShadow.call(styleDeclaration, ctx);
+      }
+
+      if (!this.caching || !charWidthsCache[cacheProp]) {
+        width = ctx.measureText(_char).width;
+        this.caching && (charWidthsCache[cacheProp] = width);
+        return width;
+      }
+
+      return charWidthsCache[cacheProp];
+    },
+
+    /**
+     * @private
+     * @param {Object} styleDeclaration
+     */
+    _applyFontStyles: function(styleDeclaration) {
+      if (!styleDeclaration.fontFamily) {
+        styleDeclaration.fontFamily = this.fontFamily;
+      }
+      if (!styleDeclaration.fontSize) {
+        styleDeclaration.fontSize = this.fontSize;
+      }
+      if (!styleDeclaration.fontWeight) {
+        styleDeclaration.fontWeight = this.fontWeight;
+      }
+      if (!styleDeclaration.fontStyle) {
+        styleDeclaration.fontStyle = this.fontStyle;
+      }
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @param {Boolean} [returnCloneOrEmpty=false]
+     * @private
+     */
+    _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) {
+      if (returnCloneOrEmpty) {
+        return (this.styles[lineIndex] && this.styles[lineIndex][charIndex])
+          ? clone(this.styles[lineIndex][charIndex])
+          : { };
+      }
+
+      return this.styles[lineIndex] && this.styles[lineIndex][charIndex] ? this.styles[lineIndex][charIndex] : null;
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @param {Object} style
+     * @private
+     */
+    _setStyleDeclaration: function(lineIndex, charIndex, style) {
+      this.styles[lineIndex][charIndex] = style;
+    },
+
+    /**
+     *
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @private
+     */
+    _deleteStyleDeclaration: function(lineIndex, charIndex) {
+      delete this.styles[lineIndex][charIndex];
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @private
+     */
+    _getLineStyle: function(lineIndex) {
+      return this.styles[lineIndex];
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Object} style
+     * @private
+     */
+    _setLineStyle: function(lineIndex, style) {
+      this.styles[lineIndex] = style;
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @private
+     */
+    _deleteLineStyle: function(lineIndex) {
+      delete this.styles[lineIndex];
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _getWidthOfChar: function(ctx, _char, lineIndex, charIndex) {
+      if (!this._isMeasuring && this.textAlign === 'justify' && this._reSpacesAndTabs.test(_char)) {
+        return this._getWidthOfSpace(ctx, lineIndex);
+      }
+      ctx.save();
+      var width = this._applyCharStylesGetWidth(ctx, _char, lineIndex, charIndex);
+      if (this.charSpacing !== 0) {
+        width += this._getWidthOfCharSpacing();
+      }
+      ctx.restore();
+      return width > 0 ? width : 0
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     */
+    _getHeightOfChar: function(ctx, lineIndex, charIndex) {
+      var style = this._getStyleDeclaration(lineIndex, charIndex);
+      return style && style.fontSize ? style.fontSize : this.fontSize;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     */
+    _getWidthOfCharsAt: function(ctx, lineIndex, charIndex) {
+      var width = 0, i, _char;
+      for (i = 0; i < charIndex; i++) {
+        _char = this._textLines[lineIndex][i];
+        width += this._getWidthOfChar(ctx, _char, lineIndex, i);
+      }
+      return width;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex line number
+     * @return {Number} Line width
+     */
+    _measureLine: function(ctx, lineIndex) {
+      this._isMeasuring = true;
+      var width = this._getWidthOfCharsAt(ctx, lineIndex, this._textLines[lineIndex].length);
+      if (this.charSpacing !== 0) {
+        width -= this._getWidthOfCharSpacing();
+      }
+      this._isMeasuring = false;
+      return width > 0 ? width : 0;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {Number} lineIndex
+     */
+    _getWidthOfSpace: function (ctx, lineIndex) {
+      if (this.__widthOfSpace[lineIndex]) {
+        return this.__widthOfSpace[lineIndex];
+      }
+      var line = this._textLines[lineIndex],
+          wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0),
+          widthDiff = this.width - wordsWidth,
+          numSpaces = line.length - line.replace(this._reSpacesAndTabs, '').length,
+          width = Math.max(widthDiff / numSpaces, ctx.measureText(' ').width);
+      this.__widthOfSpace[lineIndex] = width;
+      return width;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     * @param {String} line
+     * @param {Number} lineIndex
+     * @param {Number} charOffset
+     */
+    _getWidthOfWords: function (ctx, line, lineIndex, charOffset) {
+      var width = 0;
+
+      for (var charIndex = 0; charIndex < line.length; charIndex++) {
+        var _char = line[charIndex];
+
+        if (!_char.match(/\s/)) {
+          width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex + charOffset);
+        }
+      }
+
+      return width;
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _getHeightOfLine: function(ctx, lineIndex) {
+      if (this.__lineHeights[lineIndex]) {
+        return this.__lineHeights[lineIndex];
+      }
+
+      var line = this._textLines[lineIndex],
+          maxHeight = this._getHeightOfChar(ctx, lineIndex, 0);
+
+      for (var i = 1, len = line.length; i < len; i++) {
+        var currentCharHeight = this._getHeightOfChar(ctx, lineIndex, i);
+        if (currentCharHeight > maxHeight) {
+          maxHeight = currentCharHeight;
+        }
+      }
+      this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult;
+      return this.__lineHeights[lineIndex];
+    },
+
+    /**
+     * @private
+     * @param {CanvasRenderingContext2D} ctx Context to render on
+     */
+    _getTextHeight: function(ctx) {
+      var lineHeight, height = 0;
+      for (var i = 0, len = this._textLines.length; i < len; i++) {
+        lineHeight = this._getHeightOfLine(ctx, i);
+        height += (i === len - 1 ? lineHeight / this.lineHeight : lineHeight);
+      }
+      return height;
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @method toObject
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
+        styles: clone(this.styles, true)
+      });
+    }
+  });
+
+  /**
+   * Returns fabric.IText instance from an object representation
+   * @static
+   * @memberOf fabric.IText
+   * @param {Object} object Object to create an instance from
+   * @param {function} [callback] invoked with new instance as argument
+   * @return {fabric.IText} instance of fabric.IText
+   */
+  fabric.IText.fromObject = function(object, callback) {
+    var iText = new fabric.IText(object.text, clone(object));
+    callback && callback(iText);
+    return iText;
+  };
+})();
+
+
+(function() {
+
+  var clone = fabric.util.object.clone;
+
+  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {
+
+    /**
+     * Initializes all the interactive behavior of IText
+     */
+    initBehavior: function() {
+      this.initAddedHandler();
+      this.initRemovedHandler();
+      this.initCursorSelectionHandlers();
+      this.initDoubleClickSimulation();
+      this.mouseMoveHandler = this.mouseMoveHandler.bind(this);
+    },
+
+    /**
+     * Initializes "selected" event handler
+     */
+    initSelectedHandler: function() {
+      this.on('selected', function() {
+
+        var _this = this;
+        setTimeout(function() {
+          _this.selected = true;
+        }, 100);
+      });
+    },
+
+    /**
+     * Initializes "added" event handler
+     */
+    initAddedHandler: function() {
+      var _this = this;
+      this.on('added', function() {
+        var canvas = _this.canvas;
+        if (canvas) {
+          if (!canvas._hasITextHandlers) {
+            canvas._hasITextHandlers = true;
+            _this._initCanvasHandlers(canvas);
+          }
+          canvas._iTextInstances = canvas._iTextInstances || [];
+          canvas._iTextInstances.push(_this);
+        }
+      });
+    },
+
+    initRemovedHandler: function() {
+      var _this = this;
+      this.on('removed', function() {
+        var canvas = _this.canvas;
+        if (canvas) {
+          canvas._iTextInstances = canvas._iTextInstances || [];
+          fabric.util.removeFromArray(canvas._iTextInstances, _this);
+          if (canvas._iTextInstances.length === 0) {
+            canvas._hasITextHandlers = false;
+            _this._removeCanvasHandlers(canvas);
+          }
+        }
+      });
+    },
+
+    /**
+     * register canvas event to manage exiting on other instances
+     * @private
+     */
+    _initCanvasHandlers: function(canvas) {
+      canvas._canvasITextSelectionClearedHanlder = (function() {
+        fabric.IText.prototype.exitEditingOnOthers(canvas);
+      }).bind(this);
+      canvas._mouseUpITextHandler = (function() {
+        if (canvas._iTextInstances) {
+          canvas._iTextInstances.forEach(function(obj) {
+            obj.__isMousedown = false;
+          });
+        }
+      }).bind(this);
+      canvas.on('selection:cleared', canvas._canvasITextSelectionClearedHanlder);
+      canvas.on('object:selected', canvas._canvasITextSelectionClearedHanlder);
+      canvas.on('mouse:up', canvas._mouseUpITextHandler);
+    },
+
+    /**
+     * remove canvas event to manage exiting on other instances
+     * @private
+     */
+    _removeCanvasHandlers: function(canvas) {
+      canvas.off('selection:cleared', canvas._canvasITextSelectionClearedHanlder);
+      canvas.off('object:selected', canvas._canvasITextSelectionClearedHanlder);
+      canvas.off('mouse:up', canvas._mouseUpITextHandler);
+    },
+
+    /**
+     * @private
+     */
+    _tick: function() {
+      this._currentTickState = this._animateCursor(this, 1, this.cursorDuration, '_onTickComplete');
+    },
+
+    /**
+     * @private
+     */
+    _animateCursor: function(obj, targetOpacity, duration, completeMethod) {
+
+      var tickState;
+
+      tickState = {
+        isAborted: false,
+        abort: function() {
+          this.isAborted = true;
+        },
+      };
+
+      obj.animate('_currentCursorOpacity', targetOpacity, {
+        duration: duration,
+        onComplete: function() {
+          if (!tickState.isAborted) {
+            obj[completeMethod]();
+          }
+        },
+        onChange: function() {
+          // we do not want to animate a selection, only cursor
+          if (obj.canvas && obj.selectionStart === obj.selectionEnd) {
+            obj.renderCursorOrSelection();
+          }
+        },
+        abort: function() {
+          return tickState.isAborted;
+        }
+      });
+      return tickState;
+    },
+
+    /**
+     * @private
+     */
+    _onTickComplete: function() {
+
+      var _this = this;
+
+      if (this._cursorTimeout1) {
+        clearTimeout(this._cursorTimeout1);
+      }
+      this._cursorTimeout1 = setTimeout(function() {
+        _this._currentTickCompleteState = _this._animateCursor(_this, 0, this.cursorDuration / 2, '_tick');
+      }, 100);
+    },
+
+    /**
+     * Initializes delayed cursor
+     */
+    initDelayedCursor: function(restart) {
+      var _this = this,
+          delay = restart ? 0 : this.cursorDelay;
+
+      this.abortCursorAnimation();
+      this._currentCursorOpacity = 1;
+      this._cursorTimeout2 = setTimeout(function() {
+        _this._tick();
+      }, delay);
+    },
+
+    /**
+     * Aborts cursor animation and clears all timeouts
+     */
+    abortCursorAnimation: function() {
+      var shouldClear = this._currentTickState || this._currentTickCompleteState;
+      this._currentTickState && this._currentTickState.abort();
+      this._currentTickCompleteState && this._currentTickCompleteState.abort();
+
+      clearTimeout(this._cursorTimeout1);
+      clearTimeout(this._cursorTimeout2);
+
+      this._currentCursorOpacity = 0;
+      // to clear just itext area we need to transform the context
+      // it may not be worth it
+      if (shouldClear) {
+        this.canvas && this.canvas.clearContext(this.canvas.contextTop || this.ctx);
+      }
+
+    },
+
+    /**
+     * Selects entire text
+     */
+    selectAll: function() {
+      this.selectionStart = 0;
+      this.selectionEnd = this.text.length;
+      this._fireSelectionChanged();
+      this._updateTextarea();
+    },
+
+    /**
+     * Returns selected text
+     * @return {String}
+     */
+    getSelectedText: function() {
+      return this.text.slice(this.selectionStart, this.selectionEnd);
+    },
+
+    /**
+     * Find new selection index representing start of current word according to current selection index
+     * @param {Number} startFrom Surrent selection index
+     * @return {Number} New selection index
+     */
+    findWordBoundaryLeft: function(startFrom) {
+      var offset = 0, index = startFrom - 1;
+
+      // remove space before cursor first
+      if (this._reSpace.test(this.text.charAt(index))) {
+        while (this._reSpace.test(this.text.charAt(index))) {
+          offset++;
+          index--;
+        }
+      }
+      while (/\S/.test(this.text.charAt(index)) && index > -1) {
+        offset++;
+        index--;
+      }
+
+      return startFrom - offset;
+    },
+
+    /**
+     * Find new selection index representing end of current word according to current selection index
+     * @param {Number} startFrom Current selection index
+     * @return {Number} New selection index
+     */
+    findWordBoundaryRight: function(startFrom) {
+      var offset = 0, index = startFrom;
+
+      // remove space after cursor first
+      if (this._reSpace.test(this.text.charAt(index))) {
+        while (this._reSpace.test(this.text.charAt(index))) {
+          offset++;
+          index++;
+        }
+      }
+      while (/\S/.test(this.text.charAt(index)) && index < this.text.length) {
+        offset++;
+        index++;
+      }
+
+      return startFrom + offset;
+    },
+
+    /**
+     * Find new selection index representing start of current line according to current selection index
+     * @param {Number} startFrom Current selection index
+     * @return {Number} New selection index
+     */
+    findLineBoundaryLeft: function(startFrom) {
+      var offset = 0, index = startFrom - 1;
+
+      while (!/\n/.test(this.text.charAt(index)) && index > -1) {
+        offset++;
+        index--;
+      }
+
+      return startFrom - offset;
+    },
+
+    /**
+     * Find new selection index representing end of current line according to current selection index
+     * @param {Number} startFrom Current selection index
+     * @return {Number} New selection index
+     */
+    findLineBoundaryRight: function(startFrom) {
+      var offset = 0, index = startFrom;
+
+      while (!/\n/.test(this.text.charAt(index)) && index < this.text.length) {
+        offset++;
+        index++;
+      }
+
+      return startFrom + offset;
+    },
+
+    /**
+     * Returns number of newlines in selected text
+     * @return {Number} Number of newlines in selected text
+     */
+    getNumNewLinesInSelectedText: function() {
+      var selectedText = this.getSelectedText(),
+          numNewLines  = 0;
+
+      for (var i = 0, len = selectedText.length; i < len; i++) {
+        if (selectedText[i] === '\n') {
+          numNewLines++;
+        }
+      }
+      return numNewLines;
+    },
+
+    /**
+     * Finds index corresponding to beginning or end of a word
+     * @param {Number} selectionStart Index of a character
+     * @param {Number} direction 1 or -1
+     * @return {Number} Index of the beginning or end of a word
+     */
+    searchWordBoundary: function(selectionStart, direction) {
+      var index     = this._reSpace.test(this.text.charAt(selectionStart)) ? selectionStart - 1 : selectionStart,
+          _char     = this.text.charAt(index),
+          reNonWord = /[ \n\.,;!\?\-]/;
+
+      while (!reNonWord.test(_char) && index > 0 && index < this.text.length) {
+        index += direction;
+        _char = this.text.charAt(index);
+      }
+      if (reNonWord.test(_char) && _char !== '\n') {
+        index += direction === 1 ? 0 : 1;
+      }
+      return index;
+    },
+
+    /**
+     * Selects a word based on the index
+     * @param {Number} selectionStart Index of a character
+     */
+    selectWord: function(selectionStart) {
+      selectionStart = selectionStart || this.selectionStart;
+      var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */
+          newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */
+
+      this.selectionStart = newSelectionStart;
+      this.selectionEnd = newSelectionEnd;
+      this._fireSelectionChanged();
+      this._updateTextarea();
+      this.renderCursorOrSelection();
+    },
+
+    /**
+     * Selects a line based on the index
+     * @param {Number} selectionStart Index of a character
+     */
+    selectLine: function(selectionStart) {
+      selectionStart = selectionStart || this.selectionStart;
+      var newSelectionStart = this.findLineBoundaryLeft(selectionStart),
+          newSelectionEnd = this.findLineBoundaryRight(selectionStart);
+
+      this.selectionStart = newSelectionStart;
+      this.selectionEnd = newSelectionEnd;
+      this._fireSelectionChanged();
+      this._updateTextarea();
+    },
+
+    /**
+     * Enters editing state
+     * @return {fabric.IText} thisArg
+     * @chainable
+     */
+    enterEditing: function(e) {
+      if (this.isEditing || !this.editable) {
+        return;
+      }
+
+      if (this.canvas) {
+        this.exitEditingOnOthers(this.canvas);
+      }
+
+      this.isEditing = true;
+
+      this.initHiddenTextarea(e);
+      this.hiddenTextarea.focus();
+      this._updateTextarea();
+      this._saveEditingProps();
+      this._setEditingProps();
+      this._textBeforeEdit = this.text;
+
+      this._tick();
+      this.fire('editing:entered');
+
+      if (!this.canvas) {
+        return this;
+      }
+      this.canvas.fire('text:editing:entered', { target: this });
+      this.initMouseMoveHandler();
+      this.canvas.renderAll();
+      return this;
+    },
+
+    exitEditingOnOthers: function(canvas) {
+      if (canvas._iTextInstances) {
+        canvas._iTextInstances.forEach(function(obj) {
+          obj.selected = false;
+          if (obj.isEditing) {
+            obj.exitEditing();
+          }
+        });
+      }
+    },
+
+    /**
+     * Initializes "mousemove" event handler
+     */
+    initMouseMoveHandler: function() {
+      this.canvas.on('mouse:move', this.mouseMoveHandler);
+    },
+
+    /**
+     * @private
+     */
+    mouseMoveHandler: function(options) {
+      if (!this.__isMousedown || !this.isEditing) {
+        return;
+      }
+
+      var newSelectionStart = this.getSelectionStartFromPointer(options.e),
+          currentStart = this.selectionStart,
+          currentEnd = this.selectionEnd;
+      if (newSelectionStart === this.__selectionStartOnMouseDown) {
+        return;
+      }
+      if (newSelectionStart > this.__selectionStartOnMouseDown) {
+        this.selectionStart = this.__selectionStartOnMouseDown;
+        this.selectionEnd = newSelectionStart;
+      }
+      else {
+        this.selectionStart = newSelectionStart;
+        this.selectionEnd = this.__selectionStartOnMouseDown;
+      }
+      if (this.selectionStart !== currentStart || this.selectionEnd !== currentEnd) {
+        this._fireSelectionChanged();
+        this._updateTextarea();
+        this.renderCursorOrSelection();
+      }
+    },
+
+    /**
+     * @private
+     */
+    _setEditingProps: function() {
+      this.hoverCursor = 'text';
+
+      if (this.canvas) {
+        this.canvas.defaultCursor = this.canvas.moveCursor = 'text';
+      }
+
+      this.borderColor = this.editingBorderColor;
+
+      this.hasControls = this.selectable = false;
+      this.lockMovementX = this.lockMovementY = true;
+    },
+
+    /**
+     * @private
+     */
+    _updateTextarea: function() {
+      if (!this.hiddenTextarea || this.inCompositionMode) {
+        return;
+      }
+      this.cursorOffsetCache = { };
+      this.hiddenTextarea.value = this.text;
+      this.hiddenTextarea.selectionStart = this.selectionStart;
+      this.hiddenTextarea.selectionEnd = this.selectionEnd;
+      if (this.selectionStart === this.selectionEnd) {
+        var style = this._calcTextareaPosition();
+        this.hiddenTextarea.style.left = style.left;
+        this.hiddenTextarea.style.top = style.top;
+        this.hiddenTextarea.style.fontSize = style.fontSize;
+      }
+    },
+
+    /**
+     * @private
+     * @return {Object} style contains style for hiddenTextarea
+     */
+    _calcTextareaPosition: function() {
+      if (!this.canvas) {
+        return { x: 1, y: 1 };
+      }
+      var chars = this.text.split(''),
+          boundaries = this._getCursorBoundaries(chars, 'cursor'),
+          cursorLocation = this.get2DCursorLocation(),
+          lineIndex = cursorLocation.lineIndex,
+          charIndex = cursorLocation.charIndex,
+          charHeight = this.getCurrentCharFontSize(lineIndex, charIndex),
+          leftOffset = (lineIndex === 0 && charIndex === 0)
+                    ? this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex))
+                    : boundaries.leftOffset,
+          m = this.calcTransformMatrix(),
+          p = {
+            x: boundaries.left + leftOffset,
+            y: boundaries.top + boundaries.topOffset + charHeight
+          },
+          upperCanvas = this.canvas.upperCanvasEl,
+          maxWidth = upperCanvas.width - charHeight,
+          maxHeight = upperCanvas.height - charHeight;
+
+      p = fabric.util.transformPoint(p, m);
+      p = fabric.util.transformPoint(p, this.canvas.viewportTransform);
+
+      if (p.x < 0) {
+        p.x = 0;
+      }
+      if (p.x > maxWidth) {
+        p.x = maxWidth;
+      }
+      if (p.y < 0) {
+        p.y = 0;
+      }
+      if (p.y > maxHeight) {
+        p.y = maxHeight;
+      }
+
+      // add canvas offset on document
+      p.x += this.canvas._offset.left;
+      p.y += this.canvas._offset.top;
+
+      return { left: p.x + 'px', top: p.y + 'px', fontSize: charHeight };
+    },
+
+    /**
+     * @private
+     */
+    _saveEditingProps: function() {
+      this._savedProps = {
+        hasControls: this.hasControls,
+        borderColor: this.borderColor,
+        lockMovementX: this.lockMovementX,
+        lockMovementY: this.lockMovementY,
+        hoverCursor: this.hoverCursor,
+        defaultCursor: this.canvas && this.canvas.defaultCursor,
+        moveCursor: this.canvas && this.canvas.moveCursor
+      };
+    },
+
+    /**
+     * @private
+     */
+    _restoreEditingProps: function() {
+      if (!this._savedProps) {
+        return;
+      }
+
+      this.hoverCursor = this._savedProps.overCursor;
+      this.hasControls = this._savedProps.hasControls;
+      this.borderColor = this._savedProps.borderColor;
+      this.lockMovementX = this._savedProps.lockMovementX;
+      this.lockMovementY = this._savedProps.lockMovementY;
+
+      if (this.canvas) {
+        this.canvas.defaultCursor = this._savedProps.defaultCursor;
+        this.canvas.moveCursor = this._savedProps.moveCursor;
+      }
+    },
+
+    /**
+     * Exits from editing state
+     * @return {fabric.IText} thisArg
+     * @chainable
+     */
+    exitEditing: function() {
+      var isTextChanged = (this._textBeforeEdit !== this.text);
+      this.selected = false;
+      this.isEditing = false;
+      this.selectable = true;
+
+      this.selectionEnd = this.selectionStart;
+      this.hiddenTextarea && this.canvas && this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea);
+      this.hiddenTextarea = null;
+
+      this.abortCursorAnimation();
+      this._restoreEditingProps();
+      this._currentCursorOpacity = 0;
+
+      this.fire('editing:exited');
+      isTextChanged && this.fire('modified');
+      if (this.canvas) {
+        this.canvas.off('mouse:move', this.mouseMoveHandler);
+        this.canvas.fire('text:editing:exited', { target: this });
+        isTextChanged && this.canvas.fire('object:modified', { target: this });
+      }
+
+      return this;
+    },
+
+    /**
+     * @private
+     */
+    _removeExtraneousStyles: function() {
+      for (var prop in this.styles) {
+        if (!this._textLines[prop]) {
+          delete this.styles[prop];
+        }
+      }
+    },
+
+    /**
+     * @private
+     */
+    _removeCharsFromTo: function(start, end) {
+      while (end !== start) {
+        this._removeSingleCharAndStyle(start + 1);
+        end--;
+      }
+      this.selectionStart = start;
+      this.selectionEnd = start;
+    },
+
+    _removeSingleCharAndStyle: function(index) {
+      var isBeginningOfLine = this.text[index - 1] === '\n',
+          indexStyle        = isBeginningOfLine ? index : index - 1;
+      this.removeStyleObject(isBeginningOfLine, indexStyle);
+      this.text = this.text.slice(0, index - 1) +
+        this.text.slice(index);
+
+      this._textLines = this._splitTextIntoLines();
+    },
+
+    /**
+     * Inserts characters where cursor is (replacing selection if one exists)
+     * @param {String} _chars Characters to insert
+     * @param {Boolean} useCopiedStyle use fabric.copiedTextStyle
+     */
+    insertChars: function(_chars, useCopiedStyle) {
+      var style;
+
+      if (this.selectionEnd - this.selectionStart > 1) {
+        this._removeCharsFromTo(this.selectionStart, this.selectionEnd);
+      }
+      //short circuit for block paste
+      if (!useCopiedStyle && this.isEmptyStyles()) {
+        this.insertChar(_chars, false);
+        return;
+      }
+      for (var i = 0, len = _chars.length; i < len; i++) {
+        if (useCopiedStyle) {
+          style = fabric.copiedTextStyle[i];
+        }
+        this.insertChar(_chars[i], i < len - 1, style);
+      }
+    },
+
+    /**
+     * Inserts a character where cursor is
+     * @param {String} _char Characters to insert
+     * @param {Boolean} skipUpdate trigger rendering and updates at the end of text insert
+     * @param {Object} styleObject Style to be inserted for the new char
+     */
+    insertChar: function(_char, skipUpdate, styleObject) {
+      var isEndOfLine = this.text[this.selectionStart] === '\n';
+      this.text = this.text.slice(0, this.selectionStart) +
+        _char + this.text.slice(this.selectionEnd);
+      this._textLines = this._splitTextIntoLines();
+      this.insertStyleObjects(_char, isEndOfLine, styleObject);
+      this.selectionStart += _char.length;
+      this.selectionEnd = this.selectionStart;
+      if (skipUpdate) {
+        return;
+      }
+      this._updateTextarea();
+      this.setCoords();
+      this._fireSelectionChanged();
+      this.fire('changed');
+      this.canvas && this.canvas.fire('text:changed', { target: this });
+      this.canvas && this.canvas.renderAll();
+    },
+
+    /**
+     * Inserts new style object
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} charIndex Index of a char
+     * @param {Boolean} isEndOfLine True if it's end of line
+     */
+    insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) {
+
+      this.shiftLineStyles(lineIndex, +1);
+
+      if (!this.styles[lineIndex + 1]) {
+        this.styles[lineIndex + 1] = {};
+      }
+
+      var currentCharStyle = {},
+          newLineStyles    = {};
+
+      if (this.styles[lineIndex] && this.styles[lineIndex][charIndex - 1]) {
+        currentCharStyle = this.styles[lineIndex][charIndex - 1];
+      }
+
+      // if there's nothing after cursor,
+      // we clone current char style onto the next (otherwise empty) line
+      if (isEndOfLine) {
+        newLineStyles[0] = clone(currentCharStyle);
+        this.styles[lineIndex + 1] = newLineStyles;
+      }
+      // otherwise we clone styles of all chars
+      // after cursor onto the next line, from the beginning
+      else {
+        for (var index in this.styles[lineIndex]) {
+          if (parseInt(index, 10) >= charIndex) {
+            newLineStyles[parseInt(index, 10) - charIndex] = this.styles[lineIndex][index];
+            // remove lines from the previous line since they're on a new line now
+            delete this.styles[lineIndex][index];
+          }
+        }
+        this.styles[lineIndex + 1] = newLineStyles;
+      }
+      this._forceClearCache = true;
+    },
+
+    /**
+     * Inserts style object for a given line/char index
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} charIndex Index of a char
+     * @param {Object} [style] Style object to insert, if given
+     */
+    insertCharStyleObject: function(lineIndex, charIndex, style) {
+
+      var currentLineStyles       = this.styles[lineIndex],
+          currentLineStylesCloned = clone(currentLineStyles);
+
+      if (charIndex === 0 && !style) {
+        charIndex = 1;
+      }
+
+      // shift all char styles by 1 forward
+      // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4
+      for (var index in currentLineStylesCloned) {
+        var numericIndex = parseInt(index, 10);
+
+        if (numericIndex >= charIndex) {
+          currentLineStyles[numericIndex + 1] = currentLineStylesCloned[numericIndex];
+
+          // only delete the style if there was nothing moved there
+          if (!currentLineStylesCloned[numericIndex - 1]) {
+            delete currentLineStyles[numericIndex];
+          }
+        }
+      }
+
+      this.styles[lineIndex][charIndex] =
+        style || clone(currentLineStyles[charIndex - 1]);
+      this._forceClearCache = true;
+    },
+
+    /**
+     * Inserts style object(s)
+     * @param {String} _chars Characters at the location where style is inserted
+     * @param {Boolean} isEndOfLine True if it's end of line
+     * @param {Object} [styleObject] Style to insert
+     */
+    insertStyleObjects: function(_chars, isEndOfLine, styleObject) {
+      // removed shortcircuit over isEmptyStyles
+
+      var cursorLocation = this.get2DCursorLocation(),
+          lineIndex      = cursorLocation.lineIndex,
+          charIndex      = cursorLocation.charIndex;
+
+      if (!this._getLineStyle(lineIndex)) {
+        this._setLineStyle(lineIndex, {});
+      }
+
+      if (_chars === '\n') {
+        this.insertNewlineStyleObject(lineIndex, charIndex, isEndOfLine);
+      }
+      else {
+        this.insertCharStyleObject(lineIndex, charIndex, styleObject);
+      }
+    },
+
+    /**
+     * Shifts line styles up or down
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} offset Can be -1 or +1
+     */
+    shiftLineStyles: function(lineIndex, offset) {
+      // shift all line styles by 1 upward
+      var clonedStyles = clone(this.styles);
+      for (var line in this.styles) {
+        var numericLine = parseInt(line, 10);
+        if (numericLine > lineIndex) {
+          this.styles[numericLine + offset] = clonedStyles[numericLine];
+          if (!clonedStyles[numericLine - offset]) {
+            delete this.styles[numericLine];
+          }
+        }
+      }
+      //TODO: evaluate if delete old style lines with offset -1
+    },
+
+    /**
+     * Removes style object
+     * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line
+     * @param {Number} [index] Optional index. When not given, current selectionStart is used.
+     */
+    removeStyleObject: function(isBeginningOfLine, index) {
+
+      var cursorLocation = this.get2DCursorLocation(index),
+          lineIndex      = cursorLocation.lineIndex,
+          charIndex      = cursorLocation.charIndex;
+
+      this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex);
+    },
+
+    _getTextOnPreviousLine: function(lIndex) {
+      return this._textLines[lIndex - 1];
+    },
+
+    _removeStyleObject: function(isBeginningOfLine, cursorLocation, lineIndex, charIndex) {
+
+      if (isBeginningOfLine) {
+        var textOnPreviousLine     = this._getTextOnPreviousLine(cursorLocation.lineIndex),
+            newCharIndexOnPrevLine = textOnPreviousLine ? textOnPreviousLine.length : 0;
+
+        if (!this.styles[lineIndex - 1]) {
+          this.styles[lineIndex - 1] = {};
+        }
+        for (charIndex in this.styles[lineIndex]) {
+          this.styles[lineIndex - 1][parseInt(charIndex, 10) + newCharIndexOnPrevLine]
+            = this.styles[lineIndex][charIndex];
+        }
+        this.shiftLineStyles(cursorLocation.lineIndex, -1);
+      }
+      else {
+        var currentLineStyles = this.styles[lineIndex];
+
+        if (currentLineStyles) {
+          delete currentLineStyles[charIndex];
+        }
+        var currentLineStylesCloned = clone(currentLineStyles);
+        // shift all styles by 1 backwards
+        for (var i in currentLineStylesCloned) {
+          var numericIndex = parseInt(i, 10);
+          if (numericIndex >= charIndex && numericIndex !== 0) {
+            currentLineStyles[numericIndex - 1] = currentLineStylesCloned[numericIndex];
+            delete currentLineStyles[numericIndex];
+          }
+        }
+      }
+    },
+
+    /**
+     * Inserts new line
+     */
+    insertNewline: function() {
+      this.insertChars('\n');
+    },
+
+    /**
+     * Set the selectionStart and selectionEnd according to the ne postion of cursor
+     * mimic the key - mouse navigation when shift is pressed.
+     */
+    setSelectionStartEndWithShift: function(start, end, newSelection) {
+      if (newSelection <= start) {
+        if (end === start) {
+          this._selectionDirection = 'left';
+        }
+        else if (this._selectionDirection === 'right') {
+          this._selectionDirection = 'left';
+          this.selectionEnd = start;
+        }
+        this.selectionStart = newSelection;
+      }
+      else if (newSelection > start && newSelection < end) {
+        if (this._selectionDirection === 'right') {
+          this.selectionEnd = newSelection;
+        }
+        else {
+          this.selectionStart = newSelection;
+        }
+      }
+      else {
+        // newSelection is > selection start and end
+        if (end === start) {
+          this._selectionDirection = 'right';
+        }
+        else if (this._selectionDirection === 'left') {
+          this._selectionDirection = 'right';
+          this.selectionStart = end;
+        }
+        this.selectionEnd = newSelection;
+      }
+    },
+
+    setSelectionInBoundaries: function() {
+      var length = this.text.length;
+      if (this.selectionStart > length) {
+        this.selectionStart = length;
+      }
+      else if (this.selectionStart < 0) {
+        this.selectionStart = 0;
+      }
+      if (this.selectionEnd > length) {
+        this.selectionEnd = length;
+      }
+      else if (this.selectionEnd < 0) {
+        this.selectionEnd = 0;
+      }
+    }
+  });
+})();
+
+
+fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {
+  /**
+   * Initializes "dbclick" event handler
+   */
+  initDoubleClickSimulation: function() {
+
+    // for double click
+    this.__lastClickTime = +new Date();
+
+    // for triple click
+    this.__lastLastClickTime = +new Date();
+
+    this.__lastPointer = { };
+
+    this.on('mousedown', this.onMouseDown.bind(this));
+  },
+
+  onMouseDown: function(options) {
+
+    this.__newClickTime = +new Date();
+    var newPointer = this.canvas.getPointer(options.e);
+
+    if (this.isTripleClick(newPointer)) {
+      this.fire('tripleclick', options);
+      this._stopEvent(options.e);
+    }
+    else if (this.isDoubleClick(newPointer)) {
+      this.fire('dblclick', options);
+      this._stopEvent(options.e);
+    }
+
+    this.__lastLastClickTime = this.__lastClickTime;
+    this.__lastClickTime = this.__newClickTime;
+    this.__lastPointer = newPointer;
+    this.__lastIsEditing = this.isEditing;
+    this.__lastSelected = this.selected;
+  },
+
+  isDoubleClick: function(newPointer) {
+    return this.__newClickTime - this.__lastClickTime < 500 &&
+        this.__lastPointer.x === newPointer.x &&
+        this.__lastPointer.y === newPointer.y && this.__lastIsEditing;
+  },
+
+  isTripleClick: function(newPointer) {
+    return this.__newClickTime - this.__lastClickTime < 500 &&
+        this.__lastClickTime - this.__lastLastClickTime < 500 &&
+        this.__lastPointer.x === newPointer.x &&
+        this.__lastPointer.y === newPointer.y;
+  },
+
+  /**
+   * @private
+   */
+  _stopEvent: function(e) {
+    e.preventDefault && e.preventDefault();
+    e.stopPropagation && e.stopPropagation();
+  },
+
+  /**
+   * Initializes event handlers related to cursor or selection
+   */
+  initCursorSelectionHandlers: function() {
+    this.initSelectedHandler();
+    this.initMousedownHandler();
+    this.initMouseupHandler();
+    this.initClicks();
+  },
+
+  /**
+   * Initializes double and triple click event handlers
+   */
+  initClicks: function() {
+    this.on('dblclick', function(options) {
+      this.selectWord(this.getSelectionStartFromPointer(options.e));
+    });
+    this.on('tripleclick', function(options) {
+      this.selectLine(this.getSelectionStartFromPointer(options.e));
+    });
+  },
+
+  /**
+   * Initializes "mousedown" event handler
+   */
+  initMousedownHandler: function() {
+    this.on('mousedown', function(options) {
+      if (!this.editable) {
+        return;
+      }
+      var pointer = this.canvas.getPointer(options.e);
+
+      this.__mousedownX = pointer.x;
+      this.__mousedownY = pointer.y;
+      this.__isMousedown = true;
+
+      if (this.selected) {
+        this.setCursorByClick(options.e);
+      }
+
+      if (this.isEditing) {
+        this.__selectionStartOnMouseDown = this.selectionStart;
+        if (this.selectionStart === this.selectionEnd) {
+          this.abortCursorAnimation();
+        }
+        this.renderCursorOrSelection();
+      }
+    });
+  },
+
+  /**
+   * @private
+   */
+  _isObjectMoved: function(e) {
+    var pointer = this.canvas.getPointer(e);
+
+    return this.__mousedownX !== pointer.x ||
+           this.__mousedownY !== pointer.y;
+  },
+
+  /**
+   * Initializes "mouseup" event handler
+   */
+  initMouseupHandler: function() {
+    this.on('mouseup', function(options) {
+      this.__isMousedown = false;
+      if (!this.editable || this._isObjectMoved(options.e)) {
+        return;
+      }
+
+      if (this.__lastSelected && !this.__corner) {
+        this.enterEditing(options.e);
+        if (this.selectionStart === this.selectionEnd) {
+          this.initDelayedCursor(true);
+        }
+        else {
+          this.renderCursorOrSelection();
+        }
+      }
+      this.selected = true;
+    });
+  },
+
+  /**
+   * Changes cursor location in a text depending on passed pointer (x/y) object
+   * @param {Event} e Event object
+   */
+  setCursorByClick: function(e) {
+    var newSelection = this.getSelectionStartFromPointer(e),
+        start = this.selectionStart, end = this.selectionEnd;
+    if (e.shiftKey) {
+      this.setSelectionStartEndWithShift(start, end, newSelection);
+    }
+    else {
+      this.selectionStart = newSelection;
+      this.selectionEnd = newSelection;
+    }
+    this._fireSelectionChanged();
+    this._updateTextarea();
+  },
+
+  /**
+   * Returns index of a character corresponding to where an object was clicked
+   * @param {Event} e Event object
+   * @return {Number} Index of a character
+   */
+  getSelectionStartFromPointer: function(e) {
+    var mouseOffset = this.getLocalPointer(e),
+        prevWidth = 0,
+        width = 0,
+        height = 0,
+        charIndex = 0,
+        newSelectionStart,
+        line;
+
+    for (var i = 0, len = this._textLines.length; i < len; i++) {
+      line = this._textLines[i];
+      height += this._getHeightOfLine(this.ctx, i) * this.scaleY;
+
+      var widthOfLine = this._getLineWidth(this.ctx, i),
+          lineLeftOffset = this._getLineLeftOffset(widthOfLine);
+
+      width = lineLeftOffset * this.scaleX;
+
+      for (var j = 0, jlen = line.length; j < jlen; j++) {
+
+        prevWidth = width;
+
+        width += this._getWidthOfChar(this.ctx, line[j], i, this.flipX ? jlen - j : j) *
+                 this.scaleX;
+
+        if (height <= mouseOffset.y || width <= mouseOffset.x) {
+          charIndex++;
+          continue;
+        }
+
+        return this._getNewSelectionStartFromOffset(
+          mouseOffset, prevWidth, width, charIndex + i, jlen);
+      }
+
+      if (mouseOffset.y < height) {
+        //this happens just on end of lines.
+        return this._getNewSelectionStartFromOffset(
+          mouseOffset, prevWidth, width, charIndex + i - 1, jlen);
+      }
+    }
+
+    // clicked somewhere after all chars, so set at the end
+    if (typeof newSelectionStart === 'undefined') {
+      return this.text.length;
+    }
+  },
+
+  /**
+   * @private
+   */
+  _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) {
+
+    var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth,
+        distanceBtwNextCharAndCursor = width - mouseOffset.x,
+        offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ? 0 : 1,
+        newSelectionStart = index + offset;
+
+    // if object is horizontally flipped, mirror cursor location from the end
+    if (this.flipX) {
+      newSelectionStart = jlen - newSelectionStart;
+    }
+
+    if (newSelectionStart > this.text.length) {
+      newSelectionStart = this.text.length;
+    }
+
+    return newSelectionStart;
+  }
+});
+
+
+fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {
+
+  /**
+   * Initializes hidden textarea (needed to bring up keyboard in iOS)
+   */
+  initHiddenTextarea: function() {
+    this.hiddenTextarea = fabric.document.createElement('textarea');
+    this.hiddenTextarea.setAttribute('autocapitalize', 'off');
+    var style = this._calcTextareaPosition();
+    this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top + '; left: ' + style.left + ';'
+                                        + ' opacity: 0; width: 0px; height: 0px; z-index: -999;';
+    fabric.document.body.appendChild(this.hiddenTextarea);
+
+    fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'cut', this.cut.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this));
+    fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this));
+
+    if (!this._clickHandlerInitialized && this.canvas) {
+      fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));
+      this._clickHandlerInitialized = true;
+    }
+  },
+
+  /**
+   * @private
+   */
+  _keysMap: {
+    8:  'removeChars',
+    9:  'exitEditing',
+    27: 'exitEditing',
+    13: 'insertNewline',
+    33: 'moveCursorUp',
+    34: 'moveCursorDown',
+    35: 'moveCursorRight',
+    36: 'moveCursorLeft',
+    37: 'moveCursorLeft',
+    38: 'moveCursorUp',
+    39: 'moveCursorRight',
+    40: 'moveCursorDown',
+    46: 'forwardDelete'
+  },
+
+  /**
+   * @private
+   */
+  _ctrlKeysMapUp: {
+    67: 'copy',
+    88: 'cut'
+  },
+
+  /**
+   * @private
+   */
+  _ctrlKeysMapDown: {
+    65: 'selectAll'
+  },
+
+  onClick: function() {
+    // No need to trigger click event here, focus is enough to have the keyboard appear on Android
+    this.hiddenTextarea && this.hiddenTextarea.focus();
+  },
+
+  /**
+   * Handles keyup event
+   * @param {Event} e Event object
+   */
+  onKeyDown: function(e) {
+    if (!this.isEditing) {
+      return;
+    }
+    if (e.keyCode in this._keysMap) {
+      this[this._keysMap[e.keyCode]](e);
+    }
+    else if ((e.keyCode in this._ctrlKeysMapDown) && (e.ctrlKey || e.metaKey)) {
+      this[this._ctrlKeysMapDown[e.keyCode]](e);
+    }
+    else {
+      return;
+    }
+    e.stopImmediatePropagation();
+    e.preventDefault();
+    this.canvas && this.canvas.renderAll();
+  },
+
+  /**
+   * Handles keyup event
+   * We handle KeyUp because ie11 and edge have difficulties copy/pasting
+   * if a copy/cut event fired, keyup is dismissed
+   * @param {Event} e Event object
+   */
+  onKeyUp: function(e) {
+    if (!this.isEditing || this._copyDone) {
+      this._copyDone = false;
+      return;
+    }
+    if ((e.keyCode in this._ctrlKeysMapUp) && (e.ctrlKey || e.metaKey)) {
+      this[this._ctrlKeysMapUp[e.keyCode]](e);
+    }
+    else {
+      return;
+    }
+    e.stopImmediatePropagation();
+    e.preventDefault();
+    this.canvas && this.canvas.renderAll();
+  },
+
+  /**
+   * Handles onInput event
+   * @param {Event} e Event object
+   */
+  onInput: function(e) {
+    if (!this.isEditing || this.inCompositionMode) {
+      return;
+    }
+    var offset = this.selectionStart || 0,
+        offsetEnd = this.selectionEnd || 0,
+        textLength = this.text.length,
+        newTextLength = this.hiddenTextarea.value.length,
+        diff, charsToInsert, start;
+    if (newTextLength > textLength) {
+      //we added some character
+      start = this._selectionDirection === 'left' ? offsetEnd : offset;
+      diff = newTextLength - textLength;
+      charsToInsert = this.hiddenTextarea.value.slice(start, start + diff);
+    }
+    else {
+      //we selected a portion of text and then input something else.
+      //Internet explorer does not trigger this else
+      diff = newTextLength - textLength + offsetEnd - offset;
+      charsToInsert = this.hiddenTextarea.value.slice(offset, offset + diff);
+    }
+    this.insertChars(charsToInsert);
+    e.stopPropagation();
+  },
+
+  /**
+   * Composition start
+   */
+  onCompositionStart: function() {
+    this.inCompositionMode = true;
+    this.prevCompositionLength = 0;
+    this.compositionStart = this.selectionStart;
+  },
+
+  /**
+   * Composition end
+   */
+  onCompositionEnd: function() {
+    this.inCompositionMode = false;
+  },
+
+  /**
+   * Composition update
+   */
+  onCompositionUpdate: function(e) {
+    var data = e.data;
+    this.selectionStart = this.compositionStart;
+    this.selectionEnd = this.selectionEnd === this.selectionStart ?
+      this.compositionStart + this.prevCompositionLength : this.selectionEnd;
+    this.insertChars(data, false);
+    this.prevCompositionLength = data.length;
+  },
+
+  /**
+   * Forward delete
+   */
+  forwardDelete: function(e) {
+    if (this.selectionStart === this.selectionEnd) {
+      if (this.selectionStart === this.text.length) {
+        return;
+      }
+      this.moveCursorRight(e);
+    }
+    this.removeChars(e);
+  },
+
+  /**
+   * Copies selected text
+   * @param {Event} e Event object
+   */
+  copy: function(e) {
+    if (this.selectionStart === this.selectionEnd) {
+      //do not cut-copy if no selection
+      return;
+    }
+    var selectedText = this.getSelectedText(),
+        clipboardData = this._getClipboardData(e);
+
+    // Check for backward compatibility with old browsers
+    if (clipboardData) {
+      clipboardData.setData('text', selectedText);
+    }
+
+    fabric.copiedText = selectedText;
+    fabric.copiedTextStyle = this.getSelectionStyles(
+                          this.selectionStart,
+                          this.selectionEnd);
+    e.stopImmediatePropagation();
+    e.preventDefault();
+    this._copyDone = true;
+  },
+
+  /**
+   * Pastes text
+   * @param {Event} e Event object
+   */
+  paste: function(e) {
+    var copiedText = null,
+        clipboardData = this._getClipboardData(e),
+        useCopiedStyle = true;
+
+    // Check for backward compatibility with old browsers
+    if (clipboardData) {
+      copiedText = clipboardData.getData('text').replace(/\r/g, '');
+      if (!fabric.copiedTextStyle || fabric.copiedText !== copiedText) {
+        useCopiedStyle = false;
+      }
+    }
+    else {
+      copiedText = fabric.copiedText;
+    }
+
+    if (copiedText) {
+      this.insertChars(copiedText, useCopiedStyle);
+    }
+    e.stopImmediatePropagation();
+    e.preventDefault();
+  },
+
+  /**
+   * Cuts text
+   * @param {Event} e Event object
+   */
+  cut: function(e) {
+    if (this.selectionStart === this.selectionEnd) {
+      return;
+    }
+
+    this.copy(e);
+    this.removeChars(e);
+  },
+
+  /**
+   * @private
+   * @param {Event} e Event object
+   * @return {Object} Clipboard data object
+   */
+  _getClipboardData: function(e) {
+    return (e && e.clipboardData) || fabric.window.clipboardData;
+  },
+
+  /**
+   * Finds the width in pixels before the cursor on the same line
+   * @private
+   * @param {Number} lineIndex
+   * @param {Number} charIndex
+   * @return {Number} widthBeforeCursor width before cursor
+   */
+  _getWidthBeforeCursor: function(lineIndex, charIndex) {
+    var textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex),
+        widthOfLine = this._getLineWidth(this.ctx, lineIndex),
+        widthBeforeCursor = this._getLineLeftOffset(widthOfLine), _char;
+
+    for (var i = 0, len = textBeforeCursor.length; i < len; i++) {
+      _char = textBeforeCursor[i];
+      widthBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
+    }
+    return widthBeforeCursor;
+  },
+
+  /**
+   * Gets start offset of a selection
+   * @param {Event} e Event object
+   * @param {Boolean} isRight
+   * @return {Number}
+   */
+  getDownCursorOffset: function(e, isRight) {
+    var selectionProp = this._getSelectionForOffset(e, isRight),
+        cursorLocation = this.get2DCursorLocation(selectionProp),
+        lineIndex = cursorLocation.lineIndex;
+    // if on last line, down cursor goes to end of line
+    if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {
+      // move to the end of a text
+      return this.text.length - selectionProp;
+    }
+    var charIndex = cursorLocation.charIndex,
+        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),
+        indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor),
+        textAfterCursor = this._textLines[lineIndex].slice(charIndex);
+
+    return textAfterCursor.length + indexOnOtherLine + 2;
+  },
+
+  /**
+   * private
+   * Helps finding if the offset should be counted from Start or End
+   * @param {Event} e Event object
+   * @param {Boolean} isRight
+   * @return {Number}
+   */
+  _getSelectionForOffset: function(e, isRight) {
+    if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) {
+      return this.selectionEnd;
+    }
+    else {
+      return this.selectionStart;
+    }
+  },
+
+  /**
+   * @param {Event} e Event object
+   * @param {Boolean} isRight
+   * @return {Number}
+   */
+  getUpCursorOffset: function(e, isRight) {
+    var selectionProp = this._getSelectionForOffset(e, isRight),
+        cursorLocation = this.get2DCursorLocation(selectionProp),
+        lineIndex = cursorLocation.lineIndex;
+    if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {
+      // if on first line, up cursor goes to start of line
+      return -selectionProp;
+    }
+    var charIndex = cursorLocation.charIndex,
+        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),
+        indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor),
+        textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex);
+    // return a negative offset
+    return -this._textLines[lineIndex - 1].length + indexOnOtherLine - textBeforeCursor.length;
+  },
+
+  /**
+   * find for a given width it founds the matching character.
+   * @private
+   */
+  _getIndexOnLine: function(lineIndex, width) {
+
+    var widthOfLine = this._getLineWidth(this.ctx, lineIndex),
+        textOnLine = this._textLines[lineIndex],
+        lineLeftOffset = this._getLineLeftOffset(widthOfLine),
+        widthOfCharsOnLine = lineLeftOffset,
+        indexOnLine = 0,
+        foundMatch;
+
+    for (var j = 0, jlen = textOnLine.length; j < jlen; j++) {
+
+      var _char = textOnLine[j],
+          widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);
+
+      widthOfCharsOnLine += widthOfChar;
+
+      if (widthOfCharsOnLine > width) {
+
+        foundMatch = true;
+
+        var leftEdge = widthOfCharsOnLine - widthOfChar,
+            rightEdge = widthOfCharsOnLine,
+            offsetFromLeftEdge = Math.abs(leftEdge - width),
+            offsetFromRightEdge = Math.abs(rightEdge - width);
+
+        indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);
+
+        break;
+      }
+    }
+
+    // reached end
+    if (!foundMatch) {
+      indexOnLine = textOnLine.length - 1;
+    }
+
+    return indexOnLine;
+  },
+
+
+  /**
+   * Moves cursor down
+   * @param {Event} e Event object
+   */
+  moveCursorDown: function(e) {
+    if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {
+      return;
+    }
+    this._moveCursorUpOrDown('Down', e);
+  },
+
+  /**
+   * Moves cursor up
+   * @param {Event} e Event object
+   */
+  moveCursorUp: function(e) {
+    if (this.selectionStart === 0 && this.selectionEnd === 0) {
+      return;
+    }
+    this._moveCursorUpOrDown('Up', e);
+  },
+
+  /**
+   * Moves cursor up or down, fires the events
+   * @param {String} direction 'Up' or 'Down'
+   * @param {Event} e Event object
+   */
+  _moveCursorUpOrDown: function(direction, e) {
+    // getUpCursorOffset
+    // getDownCursorOffset
+    var action = 'get' + direction + 'CursorOffset',
+        offset = this[action](e, this._selectionDirection === 'right');
+    if (e.shiftKey) {
+      this.moveCursorWithShift(offset);
+    }
+    else {
+      this.moveCursorWithoutShift(offset);
+    }
+    if (offset !== 0) {
+      this.setSelectionInBoundaries();
+      this.abortCursorAnimation();
+      this._currentCursorOpacity = 1;
+      this.initDelayedCursor();
+      this._fireSelectionChanged();
+      this._updateTextarea();
+    }
+  },
+
+  /**
+   * Moves cursor with shift
+   * @param {Number} offset
+   */
+  moveCursorWithShift: function(offset) {
+    var newSelection = this._selectionDirection === 'left'
+    ? this.selectionStart + offset
+    : this.selectionEnd + offset;
+    this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);
+    return offset !== 0;
+  },
+
+  /**
+   * Moves cursor up without shift
+   * @param {Number} offset
+   */
+  moveCursorWithoutShift: function(offset) {
+    if (offset < 0) {
+      this.selectionStart += offset;
+      this.selectionEnd = this.selectionStart;
+    }
+    else {
+      this.selectionEnd += offset;
+      this.selectionStart = this.selectionEnd;
+    }
+    return offset !== 0;
+  },
+
+  /**
+   * Moves cursor left
+   * @param {Event} e Event object
+   */
+  moveCursorLeft: function(e) {
+    if (this.selectionStart === 0 && this.selectionEnd === 0) {
+      return;
+    }
+    this._moveCursorLeftOrRight('Left', e);
+  },
+
+  /**
+   * @private
+   * @return {Boolean} true if a change happened
+   */
+  _move: function(e, prop, direction) {
+    var newValue;
+    if (e.altKey) {
+      newValue = this['findWordBoundary' + direction](this[prop]);
+    }
+    else if (e.metaKey || e.keyCode === 35 ||  e.keyCode === 36 ) {
+      newValue = this['findLineBoundary' + direction](this[prop]);
+    }
+    else {
+      this[prop] += direction === 'Left' ? -1 : 1;
+      return true;
+    }
+    if (typeof newValue !== undefined && this[prop] !== newValue) {
+      this[prop] = newValue;
+      return true;
+    }
+  },
+
+  /**
+   * @private
+   */
+  _moveLeft: function(e, prop) {
+    return this._move(e, prop, 'Left');
+  },
+
+  /**
+   * @private
+   */
+  _moveRight: function(e, prop) {
+    return this._move(e, prop, 'Right');
+  },
+
+  /**
+   * Moves cursor left without keeping selection
+   * @param {Event} e
+   */
+  moveCursorLeftWithoutShift: function(e) {
+    var change = true;
+    this._selectionDirection = 'left';
+
+    // only move cursor when there is no selection,
+    // otherwise we discard it, and leave cursor on same place
+    if (this.selectionEnd === this.selectionStart && this.selectionStart !== 0) {
+      change = this._moveLeft(e, 'selectionStart');
+
+    }
+    this.selectionEnd = this.selectionStart;
+    return change;
+  },
+
+  /**
+   * Moves cursor left while keeping selection
+   * @param {Event} e
+   */
+  moveCursorLeftWithShift: function(e) {
+    if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {
+      return this._moveLeft(e, 'selectionEnd');
+    }
+    else if (this.selectionStart !== 0){
+      this._selectionDirection = 'left';
+      return this._moveLeft(e, 'selectionStart');
+    }
+  },
+
+  /**
+   * Moves cursor right
+   * @param {Event} e Event object
+   */
+  moveCursorRight: function(e) {
+    if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {
+      return;
+    }
+    this._moveCursorLeftOrRight('Right', e);
+  },
+
+  /**
+   * Moves cursor right or Left, fires event
+   * @param {String} direction 'Left', 'Right'
+   * @param {Event} e Event object
+   */
+  _moveCursorLeftOrRight: function(direction, e) {
+    var actionName = 'moveCursor' + direction + 'With';
+    this._currentCursorOpacity = 1;
+
+    if (e.shiftKey) {
+      actionName += 'Shift';
+    }
+    else {
+      actionName += 'outShift';
+    }
+    if (this[actionName](e)) {
+      this.abortCursorAnimation();
+      this.initDelayedCursor();
+      this._fireSelectionChanged();
+      this._updateTextarea();
+    }
+  },
+
+  /**
+   * Moves cursor right while keeping selection
+   * @param {Event} e
+   */
+  moveCursorRightWithShift: function(e) {
+    if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {
+      return this._moveRight(e, 'selectionStart');
+    }
+    else if (this.selectionEnd !== this.text.length) {
+      this._selectionDirection = 'right';
+      return this._moveRight(e, 'selectionEnd');
+    }
+  },
+
+  /**
+   * Moves cursor right without keeping selection
+   * @param {Event} e Event object
+   */
+  moveCursorRightWithoutShift: function(e) {
+    var changed = true;
+    this._selectionDirection = 'right';
+
+    if (this.selectionStart === this.selectionEnd) {
+      changed = this._moveRight(e, 'selectionStart');
+      this.selectionEnd = this.selectionStart;
+    }
+    else {
+      this.selectionStart = this.selectionEnd;
+    }
+    return changed;
+  },
+
+  /**
+   * Removes characters selected by selection
+   * @param {Event} e Event object
+   */
+  removeChars: function(e) {
+    if (this.selectionStart === this.selectionEnd) {
+      this._removeCharsNearCursor(e);
+    }
+    else {
+      this._removeCharsFromTo(this.selectionStart, this.selectionEnd);
+    }
+
+    this.setSelectionEnd(this.selectionStart);
+
+    this._removeExtraneousStyles();
+
+    this.canvas && this.canvas.renderAll();
+
+    this.setCoords();
+    this.fire('changed');
+    this.canvas && this.canvas.fire('text:changed', { target: this });
+  },
+
+  /**
+   * @private
+   * @param {Event} e Event object
+   */
+  _removeCharsNearCursor: function(e) {
+    if (this.selectionStart === 0) {
+      return;
+    }
+    if (e.metaKey) {
+      // remove all till the start of current line
+      var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);
+
+      this._removeCharsFromTo(leftLineBoundary, this.selectionStart);
+      this.setSelectionStart(leftLineBoundary);
+    }
+    else if (e.altKey) {
+      // remove all till the start of current word
+      var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);
+
+      this._removeCharsFromTo(leftWordBoundary, this.selectionStart);
+      this.setSelectionStart(leftWordBoundary);
+    }
+    else {
+      this._removeSingleCharAndStyle(this.selectionStart);
+      this.setSelectionStart(this.selectionStart - 1);
+    }
+  }
+});
+
+
+/* _TO_SVG_START_ */
+(function() {
+  var toFixed = fabric.util.toFixed,
+      NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
+
+  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {
+
+    /**
+     * @private
+     */
+    _setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) {
+      if (!this._getLineStyle(lineIndex)) {
+        fabric.Text.prototype._setSVGTextLineText.call(this,
+          lineIndex, textSpans, height, textLeftOffset, textTopOffset);
+      }
+      else {
+        this._setSVGTextLineChars(
+          lineIndex, textSpans, height, textLeftOffset, textBgRects);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) {
+
+      var chars = this._textLines[lineIndex],
+          charOffset = 0,
+          lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex)) - this.width / 2,
+          lineOffset = this._getSVGLineTopOffset(lineIndex),
+          heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);
+
+      for (var i = 0, len = chars.length; i < len; i++) {
+        var styleDecl = this._getStyleDeclaration(lineIndex, i) || { };
+
+        textSpans.push(
+          this._createTextCharSpan(
+            chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset));
+
+        var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);
+
+        if (styleDecl.textBackgroundColor) {
+          textBgRects.push(
+            this._createTextCharBg(
+              styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset));
+        }
+
+        charOffset += charWidth;
+      }
+    },
+
+    /**
+     * @private
+     */
+    _getSVGLineTopOffset: function(lineIndex) {
+      var lineTopOffset = 0, lastHeight = 0;
+      for (var j = 0; j < lineIndex; j++) {
+        lineTopOffset += this._getHeightOfLine(this.ctx, j);
+      }
+      lastHeight = this._getHeightOfLine(this.ctx, j);
+      return {
+        lineTop: lineTopOffset,
+        offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)
+      };
+    },
+
+    /**
+     * @private
+     */
+    _createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {
+      return [
+        '\t\t<rect fill="', styleDecl.textBackgroundColor,
+        '" x="', toFixed(lineLeftOffset + charOffset, NUM_FRACTION_DIGITS),
+        '" y="', toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS),
+        '" width="', toFixed(charWidth, NUM_FRACTION_DIGITS),
+        '" height="', toFixed(heightOfLine / this.lineHeight, NUM_FRACTION_DIGITS),
+        '"></rect>\n'
+      ].join('');
+    },
+
+    /**
+     * @private
+     */
+    _createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) {
+
+      var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({
+        visible: true,
+        fill: this.fill,
+        stroke: this.stroke,
+        type: 'text',
+        getSvgFilter: fabric.Object.prototype.getSvgFilter
+      }, styleDecl));
+
+      return [
+        '\t\t\t<tspan x="', toFixed(lineLeftOffset + charOffset, NUM_FRACTION_DIGITS), '" y="',
+        toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS), '" ',
+          (styleDecl.fontFamily ? 'font-family="' + styleDecl.fontFamily.replace(/"/g, '\'') + '" ' : ''),
+          (styleDecl.fontSize ? 'font-size="' + styleDecl.fontSize + '" ' : ''),
+          (styleDecl.fontStyle ? 'font-style="' + styleDecl.fontStyle + '" ' : ''),
+          (styleDecl.fontWeight ? 'font-weight="' + styleDecl.fontWeight + '" ' : ''),
+          (styleDecl.textDecoration ? 'text-decoration="' + styleDecl.textDecoration + '" ' : ''),
+        'style="', fillStyles, '">',
+        fabric.util.string.escapeXml(_char),
+        '</tspan>\n'
+      ].join('');
+    }
+  });
+})();
+/* _TO_SVG_END_ */
+
+
+(function(global) {
+
+  'use strict';
+
+  var fabric = global.fabric || (global.fabric = {}),
+      clone  = fabric.util.object.clone;
+
+  /**
+   * Textbox class, based on IText, allows the user to resize the text rectangle
+   * and wraps lines automatically. Textboxes have their Y scaling locked, the
+   * user can only change width. Height is adjusted automatically based on the
+   * wrapping of lines.
+   * @class fabric.Textbox
+   * @extends fabric.IText
+   * @mixes fabric.Observable
+   * @return {fabric.Textbox} thisArg
+   * @see {@link fabric.Textbox#initialize} for constructor definition
+   */
+  fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, {
+
+    /**
+     * Type of an object
+     * @type String
+     * @default
+     */
+    type: 'textbox',
+
+    /**
+     * Minimum width of textbox, in pixels.
+     * @type Number
+     * @default
+     */
+    minWidth: 20,
+
+    /**
+     * Minimum calculated width of a textbox, in pixels.
+     * fixed to 2 so that an empty textbox cannot go to 0
+     * and is still selectable without text.
+     * @type Number
+     * @default
+     */
+    dynamicMinWidth: 2,
+
+    /**
+     * Cached array of text wrapping.
+     * @type Array
+     */
+    __cachedLines: null,
+
+    /**
+     * Override standard Object class values
+     */
+    lockScalingY: true,
+
+    /**
+     * Override standard Object class values
+     */
+    lockScalingFlip: true,
+
+    /**
+     * Constructor. Some scaling related property values are forced. Visibility
+     * of controls is also fixed; only the rotation and width controls are
+     * made available.
+     * @param {String} text Text string
+     * @param {Object} [options] Options object
+     * @return {fabric.Textbox} thisArg
+     */
+    initialize: function(text, options) {
+      this.ctx = fabric.util.createCanvasElement().getContext('2d');
+      this.callSuper('initialize', text, options);
+      this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility());
+
+      // add width to this list of props that effect line wrapping.
+      this._dimensionAffectingProps.width = true;
+    },
+
+    /**
+     * Unlike superclass's version of this function, Textbox does not update
+     * its width.
+     * @param {CanvasRenderingContext2D} ctx Context to use for measurements
+     * @private
+     * @override
+     */
+    _initDimensions: function(ctx) {
+      if (this.__skipDimension) {
+        return;
+      }
+
+      if (!ctx) {
+        ctx = fabric.util.createCanvasElement().getContext('2d');
+        this._setTextStyles(ctx);
+      }
+
+      // clear dynamicMinWidth as it will be different after we re-wrap line
+      this.dynamicMinWidth = 0;
+
+      // wrap lines
+      this._textLines = this._splitTextIntoLines();
+      // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap
+      if (this.dynamicMinWidth > this.width) {
+        this._set('width', this.dynamicMinWidth);
+      }
+
+      // clear cache and re-calculate height
+      this._clearCache();
+      this.height = this._getTextHeight(ctx);
+    },
+
+    /**
+     * Generate an object that translates the style object so that it is
+     * broken up by visual lines (new lines and automatic wrapping).
+     * The original text styles object is broken up by actual lines (new lines only),
+     * which is only sufficient for Text / IText
+     * @private
+     */
+    _generateStyleMap: function() {
+      var realLineCount     = 0,
+          realLineCharCount = 0,
+          charCount         = 0,
+          map               = {};
+
+      for (var i = 0; i < this._textLines.length; i++) {
+        if (this.text[charCount] === '\n' && i > 0) {
+          realLineCharCount = 0;
+          charCount++;
+          realLineCount++;
+        }
+        else if (this.text[charCount] === ' ' && i > 0) {
+          // this case deals with space's that are removed from end of lines when wrapping
+          realLineCharCount++;
+          charCount++;
+        }
+
+        map[i] = { line: realLineCount, offset: realLineCharCount };
+
+        charCount += this._textLines[i].length;
+        realLineCharCount += this._textLines[i].length;
+      }
+
+      return map;
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @param {Boolean} [returnCloneOrEmpty=false]
+     * @private
+     */
+    _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) {
+      if (this._styleMap) {
+        var map = this._styleMap[lineIndex];
+        if (!map) {
+          return returnCloneOrEmpty ? { } : null;
+        }
+        lineIndex = map.line;
+        charIndex = map.offset + charIndex;
+      }
+      return this.callSuper('_getStyleDeclaration', lineIndex, charIndex, returnCloneOrEmpty);
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @param {Object} style
+     * @private
+     */
+    _setStyleDeclaration: function(lineIndex, charIndex, style) {
+      var map = this._styleMap[lineIndex];
+      lineIndex = map.line;
+      charIndex = map.offset + charIndex;
+
+      this.styles[lineIndex][charIndex] = style;
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Number} charIndex
+     * @private
+     */
+    _deleteStyleDeclaration: function(lineIndex, charIndex) {
+      var map = this._styleMap[lineIndex];
+      lineIndex = map.line;
+      charIndex = map.offset + charIndex;
+
+      delete this.styles[lineIndex][charIndex];
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @private
+     */
+    _getLineStyle: function(lineIndex) {
+      var map = this._styleMap[lineIndex];
+      return this.styles[map.line];
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @param {Object} style
+     * @private
+     */
+    _setLineStyle: function(lineIndex, style) {
+      var map = this._styleMap[lineIndex];
+      this.styles[map.line] = style;
+    },
+
+    /**
+     * @param {Number} lineIndex
+     * @private
+     */
+    _deleteLineStyle: function(lineIndex) {
+      var map = this._styleMap[lineIndex];
+      delete this.styles[map.line];
+    },
+
+    /**
+     * Wraps text using the 'width' property of Textbox. First this function
+     * splits text on newlines, so we preserve newlines entered by the user.
+     * Then it wraps each line using the width of the Textbox by calling
+     * _wrapLine().
+     * @param {CanvasRenderingContext2D} ctx Context to use for measurements
+     * @param {String} text The string of text that is split into lines
+     * @returns {Array} Array of lines
+     */
+    _wrapText: function(ctx, text) {
+      var lines = text.split(this._reNewline), wrapped = [], i;
+
+      for (i = 0; i < lines.length; i++) {
+        wrapped = wrapped.concat(this._wrapLine(ctx, lines[i], i));
+      }
+
+      return wrapped;
+    },
+
+    /**
+     * Helper function to measure a string of text, given its lineIndex and charIndex offset
+     *
+     * @param {CanvasRenderingContext2D} ctx
+     * @param {String} text
+     * @param {number} lineIndex
+     * @param {number} charOffset
+     * @returns {number}
+     * @private
+     */
+    _measureText: function(ctx, text, lineIndex, charOffset) {
+      var width = 0;
+      charOffset = charOffset || 0;
+      for (var i = 0, len = text.length; i < len; i++) {
+        width += this._getWidthOfChar(ctx, text[i], lineIndex, i + charOffset);
+      }
+      return width;
+    },
+
+    /**
+     * Wraps a line of text using the width of the Textbox and a context.
+     * @param {CanvasRenderingContext2D} ctx Context to use for measurements
+     * @param {String} text The string of text to split into lines
+     * @param {Number} lineIndex
+     * @returns {Array} Array of line(s) into which the given text is wrapped
+     * to.
+     */
+    _wrapLine: function(ctx, text, lineIndex) {
+      var lineWidth        = 0,
+          lines            = [],
+          line             = '',
+          words            = text.split(' '),
+          word             = '',
+          offset           = 0,
+          infix            = ' ',
+          wordWidth        = 0,
+          infixWidth       = 0,
+          largestWordWidth = 0,
+          lineJustStarted = true,
+          additionalSpace = this._getWidthOfCharSpacing();
+
+      for (var i = 0; i < words.length; i++) {
+        word = words[i];
+        wordWidth = this._measureText(ctx, word, lineIndex, offset);
+
+        offset += word.length;
+
+        lineWidth += infixWidth + wordWidth - additionalSpace;
+
+        if (lineWidth >= this.width && !lineJustStarted) {
+          lines.push(line);
+          line = '';
+          lineWidth = wordWidth;
+          lineJustStarted = true;
+        }
+        else {
+          lineWidth += additionalSpace;
+        }
+
+        if (!lineJustStarted) {
+          line += infix;
+        }
+        line += word;
+
+        infixWidth = this._measureText(ctx, infix, lineIndex, offset);
+        offset++;
+        lineJustStarted = false;
+        // keep track of largest word
+        if (wordWidth > largestWordWidth) {
+          largestWordWidth = wordWidth;
+        }
+      }
+
+      i && lines.push(line);
+
+      if (largestWordWidth > this.dynamicMinWidth) {
+        this.dynamicMinWidth = largestWordWidth - additionalSpace;
+      }
+
+      return lines;
+    },
+    /**
+     * Gets lines of text to render in the Textbox. This function calculates
+     * text wrapping on the fly everytime it is called.
+     * @returns {Array} Array of lines in the Textbox.
+     * @override
+     */
+    _splitTextIntoLines: function() {
+      var originalAlign = this.textAlign;
+      this.ctx.save();
+      this._setTextStyles(this.ctx);
+      this.textAlign = 'left';
+      var lines = this._wrapText(this.ctx, this.text);
+      this.textAlign = originalAlign;
+      this.ctx.restore();
+      this._textLines = lines;
+      this._styleMap = this._generateStyleMap();
+      return lines;
+    },
+
+    /**
+     * When part of a group, we don't want the Textbox's scale to increase if
+     * the group's increases. That's why we reduce the scale of the Textbox by
+     * the amount that the group's increases. This is to maintain the effective
+     * scale of the Textbox at 1, so that font-size values make sense. Otherwise
+     * the same font-size value would result in different actual size depending
+     * on the value of the scale.
+     * @param {String} key
+     * @param {*} value
+     */
+    setOnGroup: function(key, value) {
+      if (key === 'scaleX') {
+        this.set('scaleX', Math.abs(1 / value));
+        this.set('width', (this.get('width') * value) /
+          (typeof this.__oldScaleX === 'undefined' ? 1 : this.__oldScaleX));
+        this.__oldScaleX = value;
+      }
+    },
+
+    /**
+     * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start).
+     * Overrides the superclass function to take into account text wrapping.
+     *
+     * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.
+     */
+    get2DCursorLocation: function(selectionStart) {
+      if (typeof selectionStart === 'undefined') {
+        selectionStart = this.selectionStart;
+      }
+
+      var numLines = this._textLines.length,
+          removed  = 0;
+
+      for (var i = 0; i < numLines; i++) {
+        var line    = this._textLines[i],
+            lineLen = line.length;
+
+        if (selectionStart <= removed + lineLen) {
+          return {
+            lineIndex: i,
+            charIndex: selectionStart - removed
+          };
+        }
+
+        removed += lineLen;
+
+        if (this.text[removed] === '\n' || this.text[removed] === ' ') {
+          removed++;
+        }
+      }
+
+      return {
+        lineIndex: numLines - 1,
+        charIndex: this._textLines[numLines - 1].length
+      };
+    },
+
+    /**
+     * Overrides superclass function and uses text wrapping data to get cursor
+     * boundary offsets instead of the array of chars.
+     * @param {Array} chars Unused
+     * @param {String} typeOfBoundaries Can be 'cursor' or 'selection'
+     * @returns {Object} Object with 'top', 'left', and 'lineLeft' properties set.
+     */
+    _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) {
+      var topOffset      = 0,
+          leftOffset     = 0,
+          cursorLocation = this.get2DCursorLocation(),
+          lineChars      = this._textLines[cursorLocation.lineIndex].split(''),
+          lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, cursorLocation.lineIndex));
+
+      for (var i = 0; i < cursorLocation.charIndex; i++) {
+        leftOffset += this._getWidthOfChar(this.ctx, lineChars[i], cursorLocation.lineIndex, i);
+      }
+
+      for (i = 0; i < cursorLocation.lineIndex; i++) {
+        topOffset += this._getHeightOfLine(this.ctx, i);
+      }
+
+      if (typeOfBoundaries === 'cursor') {
+        topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, cursorLocation.lineIndex)
+          / this.lineHeight - this.getCurrentCharFontSize(cursorLocation.lineIndex, cursorLocation.charIndex)
+          * (1 - this._fontSizeFraction);
+      }
+
+      return {
+        top: topOffset,
+        left: leftOffset,
+        lineLeft: lineLeftOffset
+      };
+    },
+
+    getMinWidth: function() {
+      return Math.max(this.minWidth, this.dynamicMinWidth);
+    },
+
+    /**
+     * Returns object representation of an instance
+     * @method toObject
+     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
+     * @return {Object} object representation of an instance
+     */
+    toObject: function(propertiesToInclude) {
+      return this.callSuper('toObject', ['minWidth'].concat(propertiesToInclude));
+    }
+  });
+  /**
+   * Returns fabric.Textbox instance from an object representation
+   * @static
+   * @memberOf fabric.Textbox
+   * @param {Object} object Object to create an instance from
+   * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created
+   * @return {fabric.Textbox} instance of fabric.Textbox
+   */
+  fabric.Textbox.fromObject = function(object, callback) {
+    var textbox = new fabric.Textbox(object.text, clone(object));
+    callback && callback(textbox);
+    return textbox;
+  };
+  /**
+   * Returns the default controls visibility required for Textboxes.
+   * @returns {Object}
+   */
+  fabric.Textbox.getTextboxControlVisibility = function() {
+    return {
+      tl: false,
+      tr: false,
+      br: false,
+      bl: false,
+      ml: true,
+      mt: false,
+      mr: true,
+      mb: false,
+      mtr: true
+    };
+  };
+
+})(typeof exports !== 'undefined' ? exports : this);
+
+
+(function() {
+
+  /**
+   * Override _setObjectScale and add Textbox specific resizing behavior. Resizing
+   * a Textbox doesn't scale text, it only changes width and makes text wrap automatically.
+   */
+  var setObjectScaleOverridden = fabric.Canvas.prototype._setObjectScale;
+
+  fabric.Canvas.prototype._setObjectScale = function(localMouse, transform,
+                                                     lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
+
+    var t = transform.target;
+    if (t instanceof fabric.Textbox) {
+      var w = t.width * ((localMouse.x / transform.scaleX) / (t.width + t.strokeWidth));
+      if (w >= t.getMinWidth()) {
+        t.set('width', w);
+        return true;
+      }
+    }
+    else {
+      return setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform,
+        lockScalingX, lockScalingY, by, lockScalingFlip, _dim);
+    }
+  };
+
+  /**
+   * Sets controls of this group to the Textbox's special configuration if
+   * one is present in the group. Deletes _controlsVisibility otherwise, so that
+   * it gets initialized to default value at runtime.
+   */
+  fabric.Group.prototype._refreshControlsVisibility = function() {
+    if (typeof fabric.Textbox === 'undefined') {
+      return;
+    }
+    for (var i = this._objects.length; i--;) {
+      if (this._objects[i] instanceof fabric.Textbox) {
+        this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility());
+        return;
+      }
+    }
+  };
+
+  var clone = fabric.util.object.clone;
+
+  fabric.util.object.extend(fabric.Textbox.prototype, /** @lends fabric.IText.prototype */ {
+    /**
+     * @private
+     */
+    _removeExtraneousStyles: function() {
+      for (var prop in this._styleMap) {
+        if (!this._textLines[prop]) {
+          delete this.styles[this._styleMap[prop].line];
+        }
+      }
+    },
+
+    /**
+     * Inserts style object for a given line/char index
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} charIndex Index of a char
+     * @param {Object} [style] Style object to insert, if given
+     */
+    insertCharStyleObject: function(lineIndex, charIndex, style) {
+      // adjust lineIndex and charIndex
+      var map = this._styleMap[lineIndex];
+      lineIndex = map.line;
+      charIndex = map.offset + charIndex;
+
+      fabric.IText.prototype.insertCharStyleObject.apply(this, [lineIndex, charIndex, style]);
+    },
+
+    /**
+     * Inserts new style object
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} charIndex Index of a char
+     * @param {Boolean} isEndOfLine True if it's end of line
+     */
+    insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) {
+      // adjust lineIndex and charIndex
+      var map = this._styleMap[lineIndex];
+      lineIndex = map.line;
+      charIndex = map.offset + charIndex;
+
+      fabric.IText.prototype.insertNewlineStyleObject.apply(this, [lineIndex, charIndex, isEndOfLine]);
+    },
+
+    /**
+     * Shifts line styles up or down. This function is slightly different than the one in
+     * itext_behaviour as it takes into account the styleMap.
+     *
+     * @param {Number} lineIndex Index of a line
+     * @param {Number} offset Can be -1 or +1
+     */
+    shiftLineStyles: function(lineIndex, offset) {
+      // shift all line styles by 1 upward
+      var clonedStyles = clone(this.styles),
+          map          = this._styleMap[lineIndex];
+
+      // adjust line index
+      lineIndex = map.line;
+
+      for (var line in this.styles) {
+        var numericLine = parseInt(line, 10);
+
+        if (numericLine > lineIndex) {
+          this.styles[numericLine + offset] = clonedStyles[numericLine];
+
+          if (!clonedStyles[numericLine - offset]) {
+            delete this.styles[numericLine];
+          }
+        }
+      }
+      //TODO: evaluate if delete old style lines with offset -1
+    },
+
+    /**
+     * Figure out programatically the text on previous actual line (actual = separated by \n);
+     *
+     * @param {Number} lIndex
+     * @returns {String}
+     * @private
+     */
+    _getTextOnPreviousLine: function(lIndex) {
+      var textOnPreviousLine = this._textLines[lIndex - 1];
+
+      while (this._styleMap[lIndex - 2] && this._styleMap[lIndex - 2].line === this._styleMap[lIndex - 1].line) {
+        textOnPreviousLine = this._textLines[lIndex - 2] + textOnPreviousLine;
+
+        lIndex--;
+      }
+
+      return textOnPreviousLine;
+    },
+
+    /**
+     * Removes style object
+     * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line
+     * @param {Number} [index] Optional index. When not given, current selectionStart is used.
+     */
+    removeStyleObject: function(isBeginningOfLine, index) {
+
+      var cursorLocation = this.get2DCursorLocation(index),
+          map            = this._styleMap[cursorLocation.lineIndex],
+          lineIndex      = map.line,
+          charIndex      = map.offset + cursorLocation.charIndex;
+      this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex);
+    }
+  });
+})();
+
+
+(function() {
+  var override = fabric.IText.prototype._getNewSelectionStartFromOffset;
+  /**
+   * Overrides the IText implementation and adjusts character index as there is not always a linebreak
+   *
+   * @param {Number} mouseOffset
+   * @param {Number} prevWidth
+   * @param {Number} width
+   * @param {Number} index
+   * @param {Number} jlen
+   * @returns {Number}
+   */
+  fabric.IText.prototype._getNewSelectionStartFromOffset = function(mouseOffset, prevWidth, width, index, jlen) {
+    index = override.call(this, mouseOffset, prevWidth, width, index, jlen);
+
+    // the index passed into the function is padded by the amount of lines from _textLines (to account for \n)
+    // we need to remove this padding, and pad it by actual lines, and / or spaces that are meant to be there
+    var tmp     = 0,
+        removed = 0;
+
+    // account for removed characters
+    for (var i = 0; i < this._textLines.length; i++) {
+      tmp += this._textLines[i].length;
+
+      if (tmp + removed >= index) {
+        break;
+      }
+
+      if (this.text[tmp + removed] === '\n' || this.text[tmp + removed] === ' ') {
+        removed++;
+      }
+    }
+
+    return index - i + removed;
+  };
+})();
+
+
+(function() {
+
+  if (typeof document !== 'undefined' && typeof window !== 'undefined') {
+    return;
+  }
+
+  var DOMParser = require('xmldom').DOMParser,
+      URL = require('url'),
+      HTTP = require('http'),
+      HTTPS = require('https'),
+
+      Canvas = require('canvas'),
+      Image = require('canvas').Image;
+
+  /** @private */
+  function request(url, encoding, callback) {
+    var oURL = URL.parse(url);
+
+    // detect if http or https is used
+    if ( !oURL.port ) {
+      oURL.port = ( oURL.protocol.indexOf('https:') === 0 ) ? 443 : 80;
+    }
+
+    // assign request handler based on protocol
+    var reqHandler = (oURL.protocol.indexOf('https:') === 0 ) ? HTTPS : HTTP,
+        req = reqHandler.request({
+          hostname: oURL.hostname,
+          port: oURL.port,
+          path: oURL.path,
+          method: 'GET'
+        }, function(response) {
+          var body = '';
+          if (encoding) {
+            response.setEncoding(encoding);
+          }
+          response.on('end', function () {
+            callback(body);
+          });
+          response.on('data', function (chunk) {
+            if (response.statusCode === 200) {
+              body += chunk;
+            }
+          });
+        });
+
+    req.on('error', function(err) {
+      if (err.errno === process.ECONNREFUSED) {
+        fabric.log('ECONNREFUSED: connection refused to ' + oURL.hostname + ':' + oURL.port);
+      }
+      else {
+        fabric.log(err.message);
+      }
+      callback(null);
+    });
+
+    req.end();
+  }
+
+  /** @private */
+  function requestFs(path, callback) {
+    var fs = require('fs');
+    fs.readFile(path, function (err, data) {
+      if (err) {
+        fabric.log(err);
+        throw err;
+      }
+      else {
+        callback(data);
+      }
+    });
+  }
+
+  fabric.util.loadImage = function(url, callback, context) {
+    function createImageAndCallBack(data) {
+      if (data) {
+        img.src = new Buffer(data, 'binary');
+        // preserving original url, which seems to be lost in node-canvas
+        img._src = url;
+        callback && callback.call(context, img);
+      }
+      else {
+        img = null;
+        callback && callback.call(context, null, true);
+      }
+    }
+    var img = new Image();
+    if (url && (url instanceof Buffer || url.indexOf('data') === 0)) {
+      img.src = img._src = url;
+      callback && callback.call(context, img);
+    }
+    else if (url && url.indexOf('http') !== 0) {
+      requestFs(url, createImageAndCallBack);
+    }
+    else if (url) {
+      request(url, 'binary', createImageAndCallBack);
+    }
+    else {
+      callback && callback.call(context, url);
+    }
+  };
+
+  fabric.loadSVGFromURL = function(url, callback, reviver) {
+    url = url.replace(/^\n\s*/, '').replace(/\?.*$/, '').trim();
+    if (url.indexOf('http') !== 0) {
+      requestFs(url, function(body) {
+        fabric.loadSVGFromString(body.toString(), callback, reviver);
+      });
+    }
+    else {
+      request(url, '', function(body) {
+        fabric.loadSVGFromString(body, callback, reviver);
+      });
+    }
+  };
+
+  fabric.loadSVGFromString = function(string, callback, reviver) {
+    var doc = new DOMParser().parseFromString(string);
+    fabric.parseSVGDocument(doc.documentElement, function(results, options) {
+      callback && callback(results, options);
+    }, reviver);
+  };
+
+  fabric.util.getScript = function(url, callback) {
+    request(url, '', function(body) {
+      // eslint-disable-next-line no-eval
+      eval(body);
+      callback && callback();
+    });
+  };
+
+  // fabric.util.createCanvasElement = function(_, width, height) {
+  //   return new Canvas(width, height);
+  // }
+
+  /**
+   * Only available when running fabric on node.js
+   * @param {Number} width Canvas width
+   * @param {Number} height Canvas height
+   * @param {Object} [options] Options to pass to FabricCanvas.
+   * @param {Object} [nodeCanvasOptions] Options to pass to NodeCanvas.
+   * @return {Object} wrapped canvas instance
+   */
+  fabric.createCanvasForNode = function(width, height, options, nodeCanvasOptions) {
+    nodeCanvasOptions = nodeCanvasOptions || options;
+
+    var canvasEl = fabric.document.createElement('canvas'),
+        nodeCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions),
+        nodeCacheCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions);
+
+    // jsdom doesn't create style on canvas element, so here be temp. workaround
+    canvasEl.style = { };
+
+    canvasEl.width = nodeCanvas.width;
+    canvasEl.height = nodeCanvas.height;
+    options = options || { };
+    options.nodeCanvas = nodeCanvas;
+    options.nodeCacheCanvas = nodeCacheCanvas;
+    var FabricCanvas = fabric.Canvas || fabric.StaticCanvas,
+        fabricCanvas = new FabricCanvas(canvasEl, options);
+    fabricCanvas.nodeCanvas = nodeCanvas;
+    fabricCanvas.nodeCacheCanvas = nodeCacheCanvas;
+    fabricCanvas.contextContainer = nodeCanvas.getContext('2d');
+    fabricCanvas.contextCache = nodeCacheCanvas.getContext('2d');
+    fabricCanvas.Font = Canvas.Font;
+    return fabricCanvas;
+  };
+
+  var originaInitStatic = fabric.StaticCanvas.prototype._initStatic;
+  fabric.StaticCanvas.prototype._initStatic = function(el, options) {
+    el = el || fabric.document.createElement('canvas');
+    this.nodeCanvas = new Canvas(el.width, el.height);
+    this.nodeCacheCanvas = new Canvas(el.width, el.height);
+    originaInitStatic.call(this, el, options);
+    this.contextContainer = this.nodeCanvas.getContext('2d');
+    this.contextCache = this.nodeCacheCanvas.getContext('2d');
+    this.Font = Canvas.Font;
+  }
+
+  /** @ignore */
+  fabric.StaticCanvas.prototype.createPNGStream = function() {
+    return this.nodeCanvas.createPNGStream();
+  };
+
+  fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {
+    return this.nodeCanvas.createJPEGStream(opts);
+  };
+
+  fabric.StaticCanvas.prototype._initRetinaScaling = function() {
+    if (!this._isRetinaScaling()) {
+      return;
+    }
+
+    this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio);
+    this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio);
+    this.nodeCanvas.width = this.width * fabric.devicePixelRatio;
+    this.nodeCanvas.height = this.height * fabric.devicePixelRatio;
+    this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio);
+    return this;
+  };
+  if (fabric.Canvas) {
+    fabric.Canvas.prototype._initRetinaScaling = fabric.StaticCanvas.prototype._initRetinaScaling;
+  }
+
+  var origSetBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension;
+  fabric.StaticCanvas.prototype._setBackstoreDimension = function(prop, value) {
+    origSetBackstoreDimension.call(this, prop, value);
+    this.nodeCanvas[prop] = value;
+    return this;
+  };
+  if (fabric.Canvas) {
+    fabric.Canvas.prototype._setBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension;
+  }
+
+})();
+

+ 3988 - 0
public/assets/v1/common/lib/imageEditor/libs/tui-code-snippet.js

@@ -0,0 +1,3988 @@
+/*!
+ * tui-code-snippet.js
+ * @version 1.2.5
+ * @author FE Development Lab
+ * @license MIT
+ */
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["util"] = factory();
+	else
+		root["tui"] = root["tui"] || {}, root["tui"]["util"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	/**
+	 * @fileoverview
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @namespace tui.util
+	 */
+	var util = {};
+	var object = __webpack_require__(1);
+	var extend = object.extend;
+
+	extend(util, object);
+	extend(util, __webpack_require__(3));
+	extend(util, __webpack_require__(2));
+	extend(util, __webpack_require__(4));
+	extend(util, __webpack_require__(5));
+	extend(util, __webpack_require__(6));
+	extend(util, __webpack_require__(7));
+	extend(util, __webpack_require__(8));
+
+	util.browser = __webpack_require__(9);
+	util.popup = __webpack_require__(10);
+	util.formatDate = __webpack_require__(11);
+	util.defineClass = __webpack_require__(12);
+	util.defineModule = __webpack_require__(13);
+	util.defineNamespace = __webpack_require__(14);
+	util.CustomEvents = __webpack_require__(15);
+	util.Enum = __webpack_require__(16);
+	util.ExMap = __webpack_require__(17);
+	util.HashMap = __webpack_require__(19);
+	util.Map = __webpack_require__(18);
+
+	module.exports = util;
+
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has some functions for handling a plain object, json.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type.js, collection.js, array.js
+	 */
+
+	'use strict';
+
+	var type = __webpack_require__(2);
+	var array = __webpack_require__(3);
+
+	/**
+	 * The last id of stamp
+	 * @type {number}
+	 * @private
+	 */
+	var lastId = 0;
+
+	/**
+	 * Extend the target object from other objects.
+	 * @param {object} target - Object that will be extended
+	 * @param {...object} objects - Objects as sources
+	 * @returns {object} Extended object
+	 * @memberof tui.util
+	 */
+	function extend(target, objects) { // eslint-disable-line no-unused-vars
+	    var hasOwnProp = Object.prototype.hasOwnProperty;
+	    var source, prop, i, len;
+
+	    for (i = 1, len = arguments.length; i < len; i += 1) {
+	        source = arguments[i];
+	        for (prop in source) {
+	            if (hasOwnProp.call(source, prop)) {
+	                target[prop] = source[prop];
+	            }
+	        }
+	    }
+	    return target;
+	}
+
+	/**
+	 * Assign a unique id to an object
+	 * @param {object} obj - Object that will be assigned id.
+	 * @returns {number} Stamped id
+	 * @memberof tui.util
+	 */
+	function stamp(obj) {
+	    if (!obj.__fe_id) {
+	        lastId += 1;
+	        obj.__fe_id = lastId; // eslint-disable-line camelcase
+	    }
+
+	    return obj.__fe_id;
+	}
+
+	/**
+	 * Verify whether an object has a stamped id or not.
+	 * @param {object} obj - adjusted object
+	 * @returns {boolean}
+	 * @memberof tui.util
+	 */
+	function hasStamp(obj) {
+	    return type.isExisty(pick(obj, '__fe_id'));
+	}
+
+	/**
+	 * Reset the last id of stamp
+	 * @private
+	 */
+	function resetLastId() {
+	    lastId = 0;
+	}
+
+	/**
+	 * Return a key-list(array) of a given object
+	 * @param {object} obj - Object from which a key-list will be extracted
+	 * @returns {Array} A key-list(array)
+	 * @memberof tui.util
+	 */
+	function keys(obj) {
+	    var keyArray = [];
+	    var key;
+
+	    for (key in obj) {
+	        if (obj.hasOwnProperty(key)) {
+	            keyArray.push(key);
+	        }
+	    }
+
+	    return keyArray;
+	}
+
+	/**
+	 * Return the equality for multiple objects(jsonObjects).<br>
+	 *  See {@link http://stackoverflow.com/questions/1068834/object-comparison-in-javascript}
+	 * @param {...object} object - Multiple objects for comparing.
+	 * @returns {boolean} Equality
+	 * @example
+	 *
+	 *  var jsonObj1 = {name:'milk', price: 1000};
+	 *  var jsonObj2 = {name:'milk', price: 1000};
+	 *  var jsonObj3 = {name:'milk', price: 1000};
+	 *
+	 *  tui.util.compareJSON(jsonObj1, jsonObj2, jsonObj3);   // true
+	 *
+	 *
+	 *  var jsonObj4 = {name:'milk', price: 1000};
+	 *  var jsonObj5 = {name:'beer', price: 3000};
+	 *
+	 *  tui.util.compareJSON(jsonObj4, jsonObj5); // false
+
+	 * @memberof tui.util
+	 */
+	function compareJSON(object) {
+	    var argsLen = arguments.length;
+	    var i = 1;
+
+	    if (argsLen < 1) {
+	        return true;
+	    }
+
+	    for (; i < argsLen; i += 1) {
+	        if (!isSameObject(object, arguments[i])) {
+	            return false;
+	        }
+	    }
+
+	    return true;
+	}
+
+	/**
+	 * @param {*} x - object to compare
+	 * @param {*} y - object to compare
+	 * @returns {boolean} - whether object x and y is same or not
+	 * @private
+	 */
+	function isSameObject(x, y) { // eslint-disable-line complexity
+	    var leftChain = [];
+	    var rightChain = [];
+	    var p;
+
+	    // remember that NaN === NaN returns false
+	    // and isNaN(undefined) returns true
+	    if (isNaN(x) &&
+	        isNaN(y) &&
+	        type.isNumber(x) &&
+	        type.isNumber(y)) {
+	        return true;
+	    }
+
+	    // Compare primitives and functions.
+	    // Check if both arguments link to the same object.
+	    // Especially useful on step when comparing prototypes
+	    if (x === y) {
+	        return true;
+	    }
+
+	    // Works in case when functions are created in constructor.
+	    // Comparing dates is a common scenario. Another built-ins?
+	    // We can even handle functions passed across iframes
+	    if ((type.isFunction(x) && type.isFunction(y)) ||
+	        (x instanceof Date && y instanceof Date) ||
+	        (x instanceof RegExp && y instanceof RegExp) ||
+	        (x instanceof String && y instanceof String) ||
+	        (x instanceof Number && y instanceof Number)) {
+	        return x.toString() === y.toString();
+	    }
+
+	    // At last checking prototypes as good a we can
+	    if (!(x instanceof Object && y instanceof Object)) {
+	        return false;
+	    }
+
+	    if (x.isPrototypeOf(y) ||
+	        y.isPrototypeOf(x) ||
+	        x.constructor !== y.constructor ||
+	        x.prototype !== y.prototype) {
+	        return false;
+	    }
+
+	    // check for infinitive linking loops
+	    if (array.inArray(x, leftChain) > -1 ||
+	        array.inArray(y, rightChain) > -1) {
+	        return false;
+	    }
+
+	    // Quick checking of one object beeing a subset of another.
+	    for (p in y) {
+	        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
+	            return false;
+	        } else if (typeof y[p] !== typeof x[p]) {
+	            return false;
+	        }
+	    }
+
+	    //This for loop executes comparing with hasOwnProperty() and typeof for each property in 'x' object,
+	    //and verifying equality for x[property] and y[property].
+	    for (p in x) {
+	        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
+	            return false;
+	        } else if (typeof y[p] !== typeof x[p]) {
+	            return false;
+	        }
+
+	        if (typeof (x[p]) === 'object' || typeof (x[p]) === 'function') {
+	            leftChain.push(x);
+	            rightChain.push(y);
+
+	            if (!isSameObject(x[p], y[p])) {
+	                return false;
+	            }
+
+	            leftChain.pop();
+	            rightChain.pop();
+	        } else if (x[p] !== y[p]) {
+	            return false;
+	        }
+	    }
+
+	    return true;
+	}
+	/* eslint-enable complexity */
+
+	/**
+	 * Retrieve a nested item from the given object/array
+	 * @param {object|Array} obj - Object for retrieving
+	 * @param {...string|number} paths - Paths of property
+	 * @returns {*} Value
+	 * @memberof tui.util
+	 * @example
+	 *  var obj = {
+	 *      'key1': 1,
+	 *      'nested' : {
+	 *          'key1': 11,
+	 *          'nested': {
+	 *              'key1': 21
+	 *          }
+	 *      }
+	 *  };
+	 *  tui.util.pick(obj, 'nested', 'nested', 'key1'); // 21
+	 *  tui.util.pick(obj, 'nested', 'nested', 'key2'); // undefined
+	 *
+	 *  var arr = ['a', 'b', 'c'];
+	 *  tui.util.pick(arr, 1); // 'b'
+	 */
+	function pick(obj, paths) { // eslint-disable-line no-unused-vars
+	    var args = arguments;
+	    var target = args[0];
+	    var length = args.length;
+	    var i;
+	    try {
+	        for (i = 1; i < length; i += 1) {
+	            target = target[args[i]];
+	        }
+	        return target;
+	    } catch (e) {
+	        return; // eslint-disable-line consistent-return
+	    }
+	}
+
+	module.exports = {
+	    extend: extend,
+	    stamp: stamp,
+	    hasStamp: hasStamp,
+	    resetLastId: resetLastId,
+	    keys: Object.prototype.keys || keys,
+	    compareJSON: compareJSON,
+	    pick: pick
+	};
+
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports) {
+
+	/**
+	 * @fileoverview This module provides some functions to check the type of variable
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency collection.js
+	 */
+
+	'use strict';
+
+	var toString = Object.prototype.toString;
+
+	/**
+	 * Check whether the given variable is existing or not.<br>
+	 *  If the given variable is not null and not undefined, returns true.
+	 * @param {*} param - Target for checking
+	 * @returns {boolean} Is existy?
+	 * @memberof tui.util
+	 * @example
+	 *  tui.util.isExisty(''); //true
+	 *  tui.util.isExisty(0); //true
+	 *  tui.util.isExisty([]); //true
+	 *  tui.util.isExisty({}); //true
+	 *  tui.util.isExisty(null); //false
+	 *  tui.util.isExisty(undefined); //false
+	*/
+	function isExisty(param) {
+	    return !isUndefined(param) && !isNull(param);
+	}
+
+	/**
+	 * Check whether the given variable is undefined or not.<br>
+	 *  If the given variable is undefined, returns true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is undefined?
+	 * @memberof tui.util
+	 */
+	function isUndefined(obj) {
+	    return obj === undefined; // eslint-disable-line no-undefined
+	}
+
+	/**
+	 * Check whether the given variable is null or not.<br>
+	 *  If the given variable(arguments[0]) is null, returns true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is null?
+	 * @memberof tui.util
+	 */
+	function isNull(obj) {
+	    return obj === null;
+	}
+
+	/**
+	 * Check whether the given variable is truthy or not.<br>
+	 *  If the given variable is not null or not undefined or not false, returns true.<br>
+	 *  (It regards 0 as true)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is truthy?
+	 * @memberof tui.util
+	 */
+	function isTruthy(obj) {
+	    return isExisty(obj) && obj !== false;
+	}
+
+	/**
+	 * Check whether the given variable is falsy or not.<br>
+	 *  If the given variable is null or undefined or false, returns true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is falsy?
+	 * @memberof tui.util
+	 */
+	function isFalsy(obj) {
+	    return !isTruthy(obj);
+	}
+
+	/**
+	 * Check whether the given variable is an arguments object or not.<br>
+	 *  If the given variable is an arguments object, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is arguments?
+	 * @memberof tui.util
+	 */
+	function isArguments(obj) {
+	    var result = isExisty(obj) &&
+	        ((toString.call(obj) === '[object Arguments]') || !!obj.callee);
+
+	    return result;
+	}
+
+	/**
+	 * Check whether the given variable is an instance of Array or not.<br>
+	 *  If the given variable is an instance of Array, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is array instance?
+	 * @memberof tui.util
+	 */
+	function isArray(obj) {
+	    return obj instanceof Array;
+	}
+
+	/**
+	 * Check whether the given variable is an object or not.<br>
+	 *  If the given variable is an object, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is object?
+	 * @memberof tui.util
+	 */
+	function isObject(obj) {
+	    return obj === Object(obj);
+	}
+
+	/**
+	 * Check whether the given variable is a function or not.<br>
+	 *  If the given variable is a function, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is function?
+	 * @memberof tui.util
+	 */
+	function isFunction(obj) {
+	    return obj instanceof Function;
+	}
+
+	/**
+	 * Check whether the given variable is a number or not.<br>
+	 *  If the given variable is a number, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is number?
+	 * @memberof tui.util
+	 */
+	function isNumber(obj) {
+	    return typeof obj === 'number' || obj instanceof Number;
+	}
+
+	/**
+	 * Check whether the given variable is a string or not.<br>
+	 *  If the given variable is a string, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is string?
+	 * @memberof tui.util
+	 */
+	function isString(obj) {
+	    return typeof obj === 'string' || obj instanceof String;
+	}
+
+	/**
+	 * Check whether the given variable is a boolean or not.<br>
+	 *  If the given variable is a boolean, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is boolean?
+	 * @memberof tui.util
+	 */
+	function isBoolean(obj) {
+	    return typeof obj === 'boolean' || obj instanceof Boolean;
+	}
+
+
+	/**
+	 * Check whether the given variable is an instance of Array or not.<br>
+	 *  If the given variable is an instance of Array, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is an instance of array?
+	 * @memberof tui.util
+	 */
+	function isArraySafe(obj) {
+	    return toString.call(obj) === '[object Array]';
+	}
+
+	/**
+	 * Check whether the given variable is a function or not.<br>
+	 *  If the given variable is a function, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is a function?
+	 * @memberof tui.util
+	 */
+	function isFunctionSafe(obj) {
+	    return toString.call(obj) === '[object Function]';
+	}
+
+	/**
+	 * Check whether the given variable is a number or not.<br>
+	 *  If the given variable is a number, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is a number?
+	 * @memberof tui.util
+	 */
+	function isNumberSafe(obj) {
+	    return toString.call(obj) === '[object Number]';
+	}
+
+	/**
+	 * Check whether the given variable is a string or not.<br>
+	 *  If the given variable is a string, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is a string?
+	 * @memberof tui.util
+	 */
+	function isStringSafe(obj) {
+	    return toString.call(obj) === '[object String]';
+	}
+
+	/**
+	 * Check whether the given variable is a boolean or not.<br>
+	 *  If the given variable is a boolean, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is a boolean?
+	 * @memberof tui.util
+	 */
+	function isBooleanSafe(obj) {
+	    return toString.call(obj) === '[object Boolean]';
+	}
+
+	/**
+	 * Check whether the given variable is a instance of HTMLNode or not.<br>
+	 *  If the given variables is a instance of HTMLNode, return true.
+	 * @param {*} html - Target for checking
+	 * @returns {boolean} Is HTMLNode ?
+	 * @memberof tui.util
+	 */
+	function isHTMLNode(html) {
+	    if (typeof HTMLElement === 'object') {
+	        return (html && (html instanceof HTMLElement || !!html.nodeType));
+	    }
+	    return !!(html && html.nodeType);
+	}
+
+	/**
+	 * Check whether the given variable is a HTML tag or not.<br>
+	 *  If the given variables is a HTML tag, return true.
+	 * @param {*} html - Target for checking
+	 * @returns {Boolean} Is HTML tag?
+	 * @memberof tui.util
+	 */
+	function isHTMLTag(html) {
+	    if (typeof HTMLElement === 'object') {
+	        return (html && (html instanceof HTMLElement));
+	    }
+	    return !!(html && html.nodeType && html.nodeType === 1);
+	}
+
+	/**
+	 * Check whether the given variable is empty(null, undefined, or empty array, empty object) or not.<br>
+	 *  If the given variables is empty, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is empty?
+	 * @memberof tui.util
+	 */
+	function isEmpty(obj) {
+	    if (!isExisty(obj) || _isEmptyString(obj)) {
+	        return true;
+	    }
+
+	    if (isArray(obj) || isArguments(obj)) {
+	        return obj.length === 0;
+	    }
+
+	    if (isObject(obj) && !isFunction(obj)) {
+	        return !_hasOwnProperty(obj);
+	    }
+
+	    return true;
+	}
+
+	/**
+	 * Check whether given argument is empty string
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} whether given argument is empty string
+	 * @memberof tui.util
+	 * @private
+	 */
+	function _isEmptyString(obj) {
+	    return isString(obj) && obj === '';
+	}
+
+	/**
+	 * Check whether given argument has own property
+	 * @param {Object} obj - Target for checking
+	 * @returns {boolean} - whether given argument has own property
+	 * @memberof tui.util
+	 * @private
+	 */
+	function _hasOwnProperty(obj) {
+	    var key;
+	    for (key in obj) {
+	        if (obj.hasOwnProperty(key)) {
+	            return true;
+	        }
+	    }
+
+	    return false;
+	}
+
+	/**
+	 * Check whether the given variable is not empty
+	 * (not null, not undefined, or not empty array, not empty object) or not.<br>
+	 *  If the given variables is not empty, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is not empty?
+	 * @memberof tui.util
+	 */
+	function isNotEmpty(obj) {
+	    return !isEmpty(obj);
+	}
+
+	/**
+	 * Check whether the given variable is an instance of Date or not.<br>
+	 *  If the given variables is an instance of Date, return true.
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is an instance of Date?
+	 * @memberof tui.util
+	 */
+	function isDate(obj) {
+	    return obj instanceof Date;
+	}
+
+	/**
+	 * Check whether the given variable is an instance of Date or not.<br>
+	 *  If the given variables is an instance of Date, return true.<br>
+	 *  (It is used for multiple frame environments)
+	 * @param {*} obj - Target for checking
+	 * @returns {boolean} Is an instance of Date?
+	 * @memberof tui.util
+	 */
+	function isDateSafe(obj) {
+	    return toString.call(obj) === '[object Date]';
+	}
+
+	module.exports = {
+	    isExisty: isExisty,
+	    isUndefined: isUndefined,
+	    isNull: isNull,
+	    isTruthy: isTruthy,
+	    isFalsy: isFalsy,
+	    isArguments: isArguments,
+	    isArray: isArray,
+	    isArraySafe: isArraySafe,
+	    isObject: isObject,
+	    isFunction: isFunction,
+	    isFunctionSafe: isFunctionSafe,
+	    isNumber: isNumber,
+	    isNumberSafe: isNumberSafe,
+	    isDate: isDate,
+	    isDateSafe: isDateSafe,
+	    isString: isString,
+	    isStringSafe: isStringSafe,
+	    isBoolean: isBoolean,
+	    isBooleanSafe: isBooleanSafe,
+	    isHTMLNode: isHTMLNode,
+	    isHTMLTag: isHTMLTag,
+	    isEmpty: isEmpty,
+	    isNotEmpty: isNotEmpty
+	};
+
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has some functions for handling array.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+
+	var aps = Array.prototype.slice;
+	var util;
+
+	/**
+	 * Generate an integer Array containing an arithmetic progression.
+	 * @param {number} start - start index
+	 * @param {number} stop - stop index
+	 * @param {number} step - next visit index = current index + step
+	 * @returns {Array}
+	 * @memberof tui.util
+	 * @example
+	 *
+	 *   var arr = tui.util.range(5);
+	 *   console.log(arr); // [0,1,2,3,4]
+	 *
+	 *   arr = tui.util.range(1, 5);
+	 *   console.log(arr); // [1,2,3,4]
+	 *
+	 *   arr = tui.util.range(2, 10, 2);
+	 *   console.log(arr); // [2,4,6,8]
+	 *
+	 *   arr = tui.util.range(10, 2, -2);
+	 *   console.log(arr); // [10,8,6,4]
+	 */
+	var range = function(start, stop, step) {
+	    var arr = [];
+	    var flag;
+
+	    if (type.isUndefined(stop)) {
+	        stop = start || 0;
+	        start = 0;
+	    }
+
+	    step = step || 1;
+	    flag = step < 0 ? -1 : 1;
+	    stop *= flag;
+
+	    for (; start * flag < stop; start += step) {
+	        arr.push(start);
+	    }
+
+	    return arr;
+	};
+
+	/* eslint-disable valid-jsdoc */
+	/**
+	 * Zip together multiple lists into a single array
+	 * @param {...Array}
+	 * @returns {Array}
+	 * @memberof tui.util
+	 * @example
+	 *
+	 *   var result = tui.util.zip([1, 2, 3], ['a', 'b','c'], [true, false, true]);
+	 *
+	 *   console.log(result[0]); // [1, 'a', true]
+	 *   console.log(result[1]); // [2, 'b', false]
+	 *   console.log(result[2]); // [3, 'c', true]
+	 */
+	/* eslint-enable valid-jsdoc */
+	var zip = function() {
+	    var arr2d = aps.call(arguments);
+	    var result = [];
+
+	    collection.forEach(arr2d, function(arr) {
+	        collection.forEach(arr, function(value, index) {
+	            if (!result[index]) {
+	                result[index] = [];
+	            }
+	            result[index].push(value);
+	        });
+	    });
+
+	    return result;
+	};
+
+	/**
+	 * Returns the first index at which a given element can be found in the array
+	 * from start index(default 0), or -1 if it is not present.<br>
+	 * It compares searchElement to elements of the Array using strict equality
+	 * (the same method used by the ===, or triple-equals, operator).
+	 * @param {*} searchElement Element to locate in the array
+	 * @param {Array} array Array that will be traversed.
+	 * @param {number} startIndex Start index in array for searching (default 0)
+	 * @returns {number} the First index at which a given element, or -1 if it is not present
+	 * @memberof tui.util
+	 * @example
+	 *
+	 *   var arr = ['one', 'two', 'three', 'four'];
+	 *   var idx1;
+	 *   var idx2;
+	 *
+	 *   idx1 = tui.util.inArray('one', arr, 3);
+	 *   alert(idx1); // -1
+	 *
+	 *   idx2 = tui.util.inArray('one', arr);
+	 *   alert(idx2); // 0
+	 */
+	var inArray = function(searchElement, array, startIndex) {
+	    var i;
+	    var length;
+	    startIndex = startIndex || 0;
+
+	    if (!type.isArray(array)) {
+	        return -1;
+	    }
+
+	    if (Array.prototype.indexOf) {
+	        return Array.prototype.indexOf.call(array, searchElement, startIndex);
+	    }
+
+	    length = array.length;
+	    for (i = startIndex; startIndex >= 0 && i < length; i += 1) {
+	        if (array[i] === searchElement) {
+	            return i;
+	        }
+	    }
+
+	    return -1;
+	};
+
+	util = {
+	    inArray: inArray,
+	    range: range,
+	    zip: zip
+	};
+
+	module.exports = util;
+
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has some functions for handling object as collection.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type.js, object.js
+	 */
+
+	'use strict';
+
+	var type = __webpack_require__(2);
+	var object = __webpack_require__(1);
+
+	/**
+	 * Execute the provided callback once for each element present
+	 * in the array(or Array-like object) in ascending order.<br>
+	 * If the callback function returns false, the loop will be stopped.<br>
+	 * Callback function(iteratee) is invoked with three arguments:
+	 *  - The value of the element
+	 *  - The index of the element
+	 *  - The array(or Array-like object) being traversed
+	 * @param {Array} arr The array(or Array-like object) that will be traversed
+	 * @param {function} iteratee Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @memberof tui.util
+	 * @example
+	 *  var sum = 0;
+	 *
+	 *  tui.util.forEachArray([1,2,3], function(value){
+	 *      sum += value;
+	 *   });
+	 *  alert(sum); // 6
+	 */
+	function forEachArray(arr, iteratee, context) {
+	    var index = 0;
+	    var len = arr.length;
+
+	    context = context || null;
+
+	    for (; index < len; index += 1) {
+	        if (iteratee.call(context, arr[index], index, arr) === false) {
+	            break;
+	        }
+	    }
+	}
+
+
+	/**
+	 * Execute the provided callback once for each property of object which actually exist.<br>
+	 * If the callback function returns false, the loop will be stopped.<br>
+	 * Callback function(iteratee) is invoked with three arguments:
+	 *  - The value of the property
+	 *  - The name of the property
+	 *  - The object being traversed
+	 * @param {Object} obj The object that will be traversed
+	 * @param {function} iteratee  Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @memberof tui.util
+	 * @example
+	 *  var sum = 0;
+	 *
+	 *  tui.util.forEachOwnProperties({a:1,b:2,c:3}, function(value){
+	 *      sum += value;
+	 *  });
+	 *  alert(sum); // 6
+	 **/
+	function forEachOwnProperties(obj, iteratee, context) {
+	    var key;
+
+	    context = context || null;
+
+	    for (key in obj) {
+	        if (obj.hasOwnProperty(key)) {
+	            if (iteratee.call(context, obj[key], key, obj) === false) {
+	                break;
+	            }
+	        }
+	    }
+	}
+
+	/**
+	 * Execute the provided callback once for each property of object(or element of array) which actually exist.<br>
+	 * If the object is Array-like object(ex-arguments object), It needs to transform to Array.(see 'ex2' of example).<br>
+	 * If the callback function returns false, the loop will be stopped.<br>
+	 * Callback function(iteratee) is invoked with three arguments:
+	 *  - The value of the property(or The value of the element)
+	 *  - The name of the property(or The index of the element)
+	 *  - The object being traversed
+	 * @param {Object} obj The object that will be traversed
+	 * @param {function} iteratee Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @memberof tui.util
+	 * @example
+	 *  //ex1
+	 *  var sum = 0;
+	 *
+	 *  tui.util.forEach([1,2,3], function(value){
+	 *      sum += value;
+	 *  });
+	 *  alert(sum); // 6
+	 *
+	 *  //ex2 - In case of Array-like object
+	 *  function sum(){
+	 *      var factors = Array.prototype.slice.call(arguments);
+	 *      forEach(factors, function(value){
+	 *           //......
+	 *      });
+	 *  }
+	 */
+	function forEach(obj, iteratee, context) {
+	    if (type.isArray(obj)) {
+	        forEachArray(obj, iteratee, context);
+	    } else {
+	        forEachOwnProperties(obj, iteratee, context);
+	    }
+	}
+
+	/**
+	 * Execute the provided callback function once for each element in an array, in order,
+	 * and constructs a new array from the results.<br>
+	 * If the object is Array-like object(ex-arguments object),
+	 * It needs to transform to Array.(see 'ex2' of forEach example)<br>
+	 * Callback function(iteratee) is invoked with three arguments:
+	 *  - The value of the property(or The value of the element)
+	 *  - The name of the property(or The index of the element)
+	 *  - The object being traversed
+	 * @param {Object} obj The object that will be traversed
+	 * @param {function} iteratee Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @returns {Array} A new array composed of returned values from callback function
+	 * @memberof tui.util
+	 * @example
+	 *  var result = tui.util.map([0,1,2,3], function(value) {
+	 *      return value + 1;
+	 *  });
+	 *
+	 *  alert(result);  // 1,2,3,4
+	 */
+	function map(obj, iteratee, context) {
+	    var resultArray = [];
+
+	    context = context || null;
+
+	    forEach(obj, function() {
+	        resultArray.push(iteratee.apply(context, arguments));
+	    });
+
+	    return resultArray;
+	}
+
+	/**
+	 * Execute the callback function once for each element present in the array(or Array-like object or plain object).<br>
+	 * If the object is Array-like object(ex-arguments object),
+	 * It needs to transform to Array.(see 'ex2' of forEach example)<br>
+	 * Callback function(iteratee) is invoked with four arguments:
+	 *  - The previousValue
+	 *  - The currentValue
+	 *  - The index
+	 *  - The object being traversed
+	 * @param {Object} obj The object that will be traversed
+	 * @param {function} iteratee Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @returns {*} The result value
+	 * @memberof tui.util
+	 * @example
+	 *  var result = tui.util.reduce([0,1,2,3], function(stored, value) {
+	 *      return stored + value;
+	 *  });
+	 *
+	 *  alert(result); // 6
+	 */
+	function reduce(obj, iteratee, context) {
+	    var index = 0;
+	    var keys, length, store;
+
+	    context = context || null;
+
+	    if (!type.isArray(obj)) {
+	        keys = object.keys(obj);
+	        length = keys.length;
+	        store = obj[keys[index += 1]];
+	    } else {
+	        length = obj.length;
+	        store = obj[index];
+	    }
+
+	    index += 1;
+	    for (; index < length; index += 1) {
+	        store = iteratee.call(context, store, obj[keys ? keys[index] : index]);
+	    }
+
+	    return store;
+	}
+
+	/**
+	 * Transform the Array-like object to Array.<br>
+	 * In low IE (below 8), Array.prototype.slice.call is not perfect. So, try-catch statement is used.
+	 * @param {*} arrayLike Array-like object
+	 * @returns {Array} Array
+	 * @memberof tui.util
+	 * @example
+	 *  var arrayLike = {
+	 *      0: 'one',
+	 *      1: 'two',
+	 *      2: 'three',
+	 *      3: 'four',
+	 *      length: 4
+	 *  };
+	 *  var result = tui.util.toArray(arrayLike);
+	 *
+	 *  alert(result instanceof Array); // true
+	 *  alert(result); // one,two,three,four
+	 */
+	function toArray(arrayLike) {
+	    var arr;
+	    try {
+	        arr = Array.prototype.slice.call(arrayLike);
+	    } catch (e) {
+	        arr = [];
+	        forEachArray(arrayLike, function(value) {
+	            arr.push(value);
+	        });
+	    }
+	    return arr;
+	}
+
+	/**
+	 * Create a new array or plain object with all elements(or properties)
+	 * that pass the test implemented by the provided function.<br>
+	 * Callback function(iteratee) is invoked with three arguments:
+	 *  - The value of the property(or The value of the element)
+	 *  - The name of the property(or The index of the element)
+	 *  - The object being traversed
+	 * @param {Object} obj Object(plain object or Array) that will be traversed
+	 * @param {function} iteratee Callback function
+	 * @param {Object} [context] Context(this) of callback function
+	 * @returns {Object} plain object or Array
+	 * @memberof tui.util
+	 * @example
+	 *  var result1 = tui.util.filter([0,1,2,3], function(value) {
+	 *      return (value % 2 === 0);
+	 *  });
+	 *  alert(result1); // 0,2
+	 *
+	 *  var result2 = tui.util.filter({a : 1, b: 2, c: 3}, function(value) {
+	 *      return (value % 2 !== 0);
+	 *  });
+	 *  alert(result2.a); // 1
+	 *  alert(result2.b); // undefined
+	 *  alert(result2.c); // 3
+	 */
+	function filter(obj, iteratee, context) {
+	    var result, add;
+
+	    context = context || null;
+
+	    if (!type.isObject(obj) || !type.isFunction(iteratee)) {
+	        throw new Error('wrong parameter');
+	    }
+
+	    if (type.isArray(obj)) {
+	        result = [];
+	        add = function(subResult, args) {
+	            subResult.push(args[0]);
+	        };
+	    } else {
+	        result = {};
+	        add = function(subResult, args) {
+	            subResult[args[1]] = args[0];
+	        };
+	    }
+
+	    forEach(obj, function() {
+	        if (iteratee.apply(context, arguments)) {
+	            add(result, arguments);
+	        }
+	    }, context);
+
+	    return result;
+	}
+
+	/**
+	 * fetching a property
+	 * @param {Array} arr target collection
+	 * @param {String|Number} property property name
+	 * @returns {Array}
+	 * @memberof tui.util
+	 * @example
+	 *   var objArr = [
+	 *         {'abc': 1, 'def': 2, 'ghi': 3},
+	 *         {'abc': 4, 'def': 5, 'ghi': 6},
+	 *         {'abc': 7, 'def': 8, 'ghi': 9}
+	 *       ];
+	 *   var arr2d = [
+	 *         [1, 2, 3],
+	 *         [4, 5, 6],
+	 *         [7, 8, 9]
+	 *       ];
+	 *   var result;
+	 *
+	 *   result = tui.util.pluck(objArr, 'abc');
+	 *   console.log(result) // [1, 4, 7]
+	 *
+	 *   result = tui.util.pluck(arr2d, 2);
+	 *   console.log(result) // [3, 6, 9]
+	 */
+	function pluck(arr, property) {
+	    var result = map(arr, function(item) {
+	        return item[property];
+	    });
+	    return result;
+	}
+
+	module.exports = {
+	    forEachOwnProperties: forEachOwnProperties,
+	    forEachArray: forEachArray,
+	    forEach: forEach,
+	    toArray: toArray,
+	    map: map,
+	    reduce: reduce,
+	    filter: filter,
+	    pluck: pluck
+	};
+
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports) {
+
+	/**
+	 * @fileoverview This module provides a bind() function for context binding.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 */
+
+	'use strict';
+
+	/**
+	 * Create a new function that, when called, has its this keyword set to the provided value.
+	 * @param {function} fn A original function before binding
+	 * @param {*} obj context of function in arguments[0]
+	 * @returns {function()} A new bound function with context that is in arguments[1]
+	 * @memberof tui.util
+	 */
+	function bind(fn, obj) {
+	    var slice = Array.prototype.slice;
+	    var args;
+
+	    if (fn.bind) {
+	        return fn.bind.apply(fn, slice.call(arguments, 1));
+	    }
+
+	    /* istanbul ignore next */
+	    args = slice.call(arguments, 2);
+
+	    /* istanbul ignore next */
+	    return function() {
+	        /* istanbul ignore next */
+	        return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
+	    };
+	}
+
+	module.exports = {
+	    bind: bind
+	};
+
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports) {
+
+	/**
+	 * @fileoverview This module provides some simple function for inheritance.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 */
+
+	'use strict';
+
+	/**
+	 * Create a new object with the specified prototype object and properties.
+	 * @param {Object} obj This object will be a prototype of the newly-created object.
+	 * @returns {Object}
+	 * @memberof tui.util
+	 */
+	function createObject(obj) {
+	    function F() {} // eslint-disable-line require-jsdoc
+	    F.prototype = obj;
+	    return new F();
+	}
+
+	/**
+	 * Provide a simple inheritance in prototype-oriented.<br>
+	 * Caution :
+	 *  Don't overwrite the prototype of child constructor.
+	 *
+	 * @param {function} subType Child constructor
+	 * @param {function} superType Parent constructor
+	 * @memberof tui.util
+	 * @example
+	 *  // Parent constructor
+	 *  function Animal(leg) {
+	 *      this.leg = leg;
+	 *  }
+	 *
+	 *  Animal.prototype.growl = function() {
+	 *      // ...
+	 *  };
+	 *
+	 *  // Child constructor
+	 *  function Person(name) {
+	 *      this.name = name;
+	 *  }
+	 *
+	 *  // Inheritance
+	 *  core.inherit(Person, Animal);
+	 *
+	 *  // After this inheritance, please use only the extending of property.
+	 *  // Do not overwrite prototype.
+	 *  Person.prototype.walk = function(direction) {
+	 *      // ...
+	 *  };
+	 */
+	function inherit(subType, superType) {
+	    var prototype = createObject(superType.prototype);
+	    prototype.constructor = subType;
+	    subType.prototype = prototype;
+	}
+
+	module.exports = {
+	    createObject: createObject,
+	    inherit: inherit
+	};
+
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has some functions for handling the string.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var object = __webpack_require__(1);
+	/**
+	 * Transform the given HTML Entity string into plain string
+	 * @param {String} htmlEntity - HTML Entity type string
+	 * @returns {String} Plain string
+	 * @memberof tui.util
+	 * @example
+	 *  var htmlEntityString = "A &#39;quote&#39; is &lt;b&gt;bold&lt;/b&gt;"
+	 *  var result = decodeHTMLEntity(htmlEntityString); //"A 'quote' is <b>bold</b>"
+	 */
+	function decodeHTMLEntity(htmlEntity) {
+	    var entities = {
+	        '&quot;': '"',
+	        '&amp;': '&',
+	        '&lt;': '<',
+	        '&gt;': '>',
+	        '&#39;': '\'',
+	        '&nbsp;': ' '
+	    };
+	    return htmlEntity.replace(/&amp;|&lt;|&gt;|&quot;|&#39;|&nbsp;/g, function(m0) {
+	        return entities[m0] ? entities[m0] : m0;
+	    });
+	}
+
+	/**
+	 * Transform the given string into HTML Entity string
+	 * @param {String} html - String for encoding
+	 * @returns {String} HTML Entity
+	 * @memberof tui.util
+	 * @example
+	 *  var htmlEntityString = "<script> alert('test');</script><a href='test'>";
+	 *  var result = encodeHTMLEntity(htmlEntityString);
+	 * //"&lt;script&gt; alert(&#39;test&#39;);&lt;/script&gt;&lt;a href=&#39;test&#39;&gt;"
+	 */
+	function encodeHTMLEntity(html) {
+	    var entities = {'"': 'quot', '&': 'amp', '<': 'lt', '>': 'gt', '\'': '#39'};
+	    return html.replace(/[<>&"']/g, function(m0) {
+	        return entities[m0] ? '&' + entities[m0] + ';' : m0;
+	    });
+	}
+
+	/**
+	 * Return whether the string capable to transform into plain string is in the given string or not.
+	 * @param {String} string - test string
+	 * @memberof tui.util
+	 * @returns {boolean}
+	 */
+	function hasEncodableString(string) {
+	    return (/[<>&"']/).test(string);
+	}
+
+	/**
+	 * Return duplicate charters
+	 * @param {string} operandStr1 The operand string
+	 * @param {string} operandStr2 The operand string
+	 * @private
+	 * @memberof tui.util
+	 * @returns {string}
+	 * @example
+	 * tui.util.getDuplicatedChar('fe dev', 'nhn entertainment');
+	 * => 'e'
+	 * tui.util.getDuplicatedChar('fdsa', 'asdf');
+	 * => 'asdf'
+	 */
+	function getDuplicatedChar(operandStr1, operandStr2) {
+	    var i = 0;
+	    var len = operandStr1.length;
+	    var pool = {};
+	    var dupl, key;
+
+	    for (; i < len; i += 1) {
+	        key = operandStr1.charAt(i);
+	        pool[key] = 1;
+	    }
+
+	    for (i = 0, len = operandStr2.length; i < len; i += 1) {
+	        key = operandStr2.charAt(i);
+	        if (pool[key]) {
+	            pool[key] += 1;
+	        }
+	    }
+
+	    pool = collection.filter(pool, function(item) {
+	        return item > 1;
+	    });
+
+	    pool = object.keys(pool).sort();
+	    dupl = pool.join('');
+
+	    return dupl;
+	}
+
+	module.exports = {
+	    decodeHTMLEntity: decodeHTMLEntity,
+	    encodeHTMLEntity: encodeHTMLEntity,
+	    hasEncodableString: hasEncodableString,
+	    getDuplicatedChar: getDuplicatedChar
+	};
+
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports) {
+
+	/**
+	 * @fileoverview collections of some technic methods.
+	 * @author NHN Ent. FE Development Lab <e0242.nhnent.com>
+	 */
+
+	'use strict';
+	var tricks = {};
+	var aps = Array.prototype.slice;
+
+	/**
+	 * Creates a debounced function that delays invoking fn until after delay milliseconds has elapsed
+	 * since the last time the debouced function was invoked.
+	 * @param {function} fn The function to debounce.
+	 * @param {number} [delay=0] The number of milliseconds to delay
+	 * @memberof tui.util
+	 * @returns {function} debounced function.
+	 * @example
+	 *
+	 * function someMethodToInvokeDebounced() {}
+	 *
+	 * var debounced = tui.util.debounce(someMethodToInvokeDebounced, 300);
+	 *
+	 * // invoke repeatedly
+	 * debounced();
+	 * debounced();
+	 * debounced();
+	 * debounced();
+	 * debounced();
+	 * debounced();    // last invoke of debounced()
+	 *
+	 * // invoke someMethodToInvokeDebounced() after 300 milliseconds.
+	 */
+	function debounce(fn, delay) {
+	    var timer, args;
+
+	    /* istanbul ignore next */
+	    delay = delay || 0;
+
+	    function debounced() { // eslint-disable-line require-jsdoc
+	        args = aps.call(arguments);
+
+	        window.clearTimeout(timer);
+	        timer = window.setTimeout(function() {
+	            fn.apply(null, args);
+	        }, delay);
+	    }
+
+	    return debounced;
+	}
+
+	/**
+	 * return timestamp
+	 * @memberof tui.util
+	 * @returns {number} The number of milliseconds from Jan. 1970 00:00:00 (GMT)
+	 */
+	function timestamp() {
+	    return Number(new Date());
+	}
+
+	/**
+	 * Creates a throttled function that only invokes fn at most once per every interval milliseconds.
+	 *
+	 * You can use this throttle short time repeatedly invoking functions. (e.g MouseMove, Resize ...)
+	 *
+	 * if you need reuse throttled method. you must remove slugs (e.g. flag variable) related with throttling.
+	 * @param {function} fn function to throttle
+	 * @param {number} [interval=0] the number of milliseconds to throttle invocations to.
+	 * @memberof tui.util
+	 * @returns {function} throttled function
+	 * @example
+	 *
+	 * function someMethodToInvokeThrottled() {}
+	 *
+	 * var throttled = tui.util.throttle(someMethodToInvokeThrottled, 300);
+	 *
+	 * // invoke repeatedly
+	 * throttled();    // invoke (leading)
+	 * throttled();
+	 * throttled();    // invoke (near 300 milliseconds)
+	 * throttled();
+	 * throttled();
+	 * throttled();    // invoke (near 600 milliseconds)
+	 * // ...
+	 * // invoke (trailing)
+	 *
+	 * // if you need reuse throttled method. then invoke reset()
+	 * throttled.reset();
+	 */
+	function throttle(fn, interval) {
+	    var base;
+	    var isLeading = true;
+	    var tick = function(_args) {
+	        fn.apply(null, _args);
+	        base = null;
+	    };
+	    var debounced, stamp, args;
+
+	    /* istanbul ignore next */
+	    interval = interval || 0;
+
+	    debounced = tricks.debounce(tick, interval);
+
+	    function throttled() { // eslint-disable-line require-jsdoc
+	        args = aps.call(arguments);
+
+	        if (isLeading) {
+	            tick(args);
+	            isLeading = false;
+	            return;
+	        }
+
+	        stamp = tricks.timestamp();
+
+	        base = base || stamp;
+
+	        // pass array directly because `debounce()`, `tick()` are already use
+	        // `apply()` method to invoke developer's `fn` handler.
+	        //
+	        // also, this `debounced` line invoked every time for implements
+	        // `trailing` features.
+	        debounced(args);
+
+	        if ((stamp - base) >= interval) {
+	            tick(args);
+	        }
+	    }
+
+	    function reset() { // eslint-disable-line require-jsdoc
+	        isLeading = true;
+	        base = null;
+	    }
+
+	    throttled.reset = reset;
+	    return throttled;
+	}
+
+	tricks.timestamp = timestamp;
+	tricks.debounce = debounce;
+	tricks.throttle = throttle;
+
+	module.exports = tricks;
+
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports) {
+
+	/**
+	 * @fileoverview This module detects the kind of well-known browser and version.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 */
+
+	'use strict';
+
+	/**
+	 * This object has an information that indicate the kind of browser.<br>
+	 * The list below is a detectable browser list.
+	 *  - ie8 ~ ie11
+	 *  - chrome
+	 *  - firefox
+	 *  - safari
+	 *  - edge
+	 * @memberof tui.util
+	 * @example
+	 *   tui.util.browser.chrome === true;    // chrome
+	 *  tui.util.browser.firefox === true;    // firefox
+	 *  tui.util.browser.safari === true;    // safari
+	 *  tui.util.browser.msie === true;    // IE
+	 *  tui.util.browser.edge === true;     // edge
+	 *  tui.util.browser.others === true;    // other browser
+	 *  tui.util.browser.version;    // browser version
+	 */
+	var browser = {
+	    chrome: false,
+	    firefox: false,
+	    safari: false,
+	    msie: false,
+	    edge: false,
+	    others: false,
+	    version: 0
+	};
+
+	var nav = window.navigator;
+	var appName = nav.appName.replace(/\s/g, '_');
+	var userAgent = nav.userAgent;
+
+	var rIE = /MSIE\s([0-9]+[.0-9]*)/;
+	var rIE11 = /Trident.*rv:11\./;
+	var rEdge = /Edge\/(\d+)\./;
+	var versionRegex = {
+	    firefox: /Firefox\/(\d+)\./,
+	    chrome: /Chrome\/(\d+)\./,
+	    safari: /Version\/([\d\.]+).*Safari\/(\d+)/
+	};
+
+	var key, tmp;
+
+	var detector = {
+	    Microsoft_Internet_Explorer: function() { // eslint-disable-line camelcase
+	        var detectedVersion = userAgent.match(rIE);
+
+	        if (detectedVersion) { // ie8 ~ ie10
+	            browser.msie = true;
+	            browser.version = parseFloat(detectedVersion[1]);
+	        } else { // no version information
+	            browser.others = true;
+	        }
+	    },
+	    Netscape: function() { // eslint-disable-line complexity
+	        var detected = false;
+
+	        if (rIE11.exec(userAgent)) {
+	            browser.msie = true;
+	            browser.version = 11;
+	            detected = true;
+	        } else if (rEdge.exec(userAgent)) {
+	            browser.edge = true;
+	            browser.version = userAgent.match(rEdge)[1];
+	            detected = true;
+	        } else {
+	            for (key in versionRegex) {
+	                if (versionRegex.hasOwnProperty(key)) {
+	                    tmp = userAgent.match(versionRegex[key]);
+	                    if (tmp && tmp.length > 1) { // eslint-disable-line max-depth
+	                        browser[key] = detected = true;
+	                        browser.version = parseFloat(tmp[1] || 0);
+	                        break;
+	                    }
+	                }
+	            }
+	        }
+	        if (!detected) {
+	            browser.others = true;
+	        }
+	    }
+	};
+
+	var fn = detector[appName];
+
+	if (fn) {
+	    detector[appName]();
+	}
+
+	module.exports = browser;
+
+
+/***/ }),
+/* 10 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has some methods for handling popup-window
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency browser.js, type.js, object.js, collection.js, func.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+	var func = __webpack_require__(5);
+	var browser = __webpack_require__(9);
+	var object = __webpack_require__(1);
+
+	var popupId = 0;
+
+	/**
+	 * Popup management class
+	 * @constructor
+	 * @memberof tui.util
+	 */
+	function Popup() {
+	    /**
+	     * Caching the window-contexts of opened popups
+	     * @type {Object}
+	     */
+	    this.openedPopup = {};
+
+	    /**
+	     * In IE7, an error occurs when the closeWithParent property attaches to window object.<br>
+	     * So, It is for saving the value of closeWithParent instead of attaching to window object.
+	     * @type {Object}
+	     */
+	    this.closeWithParentPopup = {};
+
+	    /**
+	     * Post data bridge for IE11 popup
+	     * @type {string}
+	     */
+	    this.postBridgeUrl = '';
+	}
+
+	/**********
+	 * public methods
+	 **********/
+
+	/**
+	 * Returns a popup-list administered by current window.
+	 * @param {string} [key] The key of popup.
+	 * @returns {Object} popup window list object
+	 */
+	Popup.prototype.getPopupList = function(key) {
+	    var target;
+	    if (type.isExisty(key)) {
+	        target = this.openedPopup[key];
+	    } else {
+	        target = this.openedPopup;
+	    }
+	    return target;
+	};
+
+	/**
+	 * Open popup
+	 * Caution:
+	 *  In IE11, when transfer data to popup by POST, must set the postBridgeUrl.
+	 *
+	 * @param {string} url - popup url
+	 * @param {Object} options - popup options
+	 *     @param {string} [options.popupName] - Key of popup window.<br>
+	 *      If the key is set, when you try to open by this key, the popup of this key is focused.<br>
+	 *      Or else a new popup window having this key is opened.
+	 *
+	 *     @param {string} [options.popupOptionStr=""] - Option string of popup window<br>
+	 *      It is same with the third parameter of window.open() method.<br>
+	 *      See {@link http://www.w3schools.com/jsref/met_win_open.asp}
+	 *
+	 *     @param {boolean} [options.closeWithParent=true] - Is closed when parent window closed?
+	 *
+	 *     @param {boolean} [options.useReload=false] - This property indicates whether reload the popup or not.<br>
+	 *      If true, the popup will be reloaded when you try to re-open the popup that has been opened.<br>
+	 *      When transmit the POST-data, some browsers alert a message for confirming whether retransmit or not.
+	 *
+	 *     @param {string} [options.postBridgeUrl='']
+	 *      Use this url to avoid a certain bug occuring when transmitting POST data to the popup in IE11.<br>
+	 *      This specific buggy situation is known to happen because IE11 tries to open the requested url<br>
+	 *      not in a new popup window as intended, but in a new tab.<br>
+	 *      See {@link http://wiki.nhnent.com/pages/viewpage.action?pageId=240562844}
+	 *
+	 *     @param {string} [options.method=get]
+	 *     The method of transmission when the form-data is transmitted to popup-window.
+	 *
+	 *     @param {Object} [options.param=null]
+	 *     Using as parameters for transmission when the form-data is transmitted to popup-window.
+	 */
+	Popup.prototype.openPopup = function(url, options) { // eslint-disable-line complexity
+	    var popup, formElement, useIEPostBridge;
+
+	    options = object.extend({
+	        popupName: 'popup_' + popupId + '_' + Number(new Date()),
+	        popupOptionStr: '',
+	        useReload: true,
+	        closeWithParent: true,
+	        method: 'get',
+	        param: {}
+	    }, options || {});
+
+	    options.method = options.method.toUpperCase();
+
+	    this.postBridgeUrl = options.postBridgeUrl || this.postBridgeUrl;
+
+	    useIEPostBridge = options.method === 'POST' && options.param &&
+	            browser.msie && browser.version === 11;
+
+	    if (!type.isExisty(url)) {
+	        throw new Error('Popup#open() need popup url.');
+	    }
+
+	    popupId += 1;
+
+	    /*
+	     * In form-data transmission
+	     * 1. Create a form before opening a popup.
+	     * 2. Transmit the form-data.
+	     * 3. Remove the form after transmission.
+	     */
+	    if (options.param) {
+	        if (options.method === 'GET') {
+	            url = url + (/\?/.test(url) ? '&' : '?') + this._parameterize(options.param);
+	        } else if (options.method === 'POST') {
+	            if (!useIEPostBridge) {
+	                formElement = this.createForm(url, options.param, options.method, options.popupName);
+	                url = 'about:blank';
+	            }
+	        }
+	    }
+
+	    popup = this.openedPopup[options.popupName];
+
+	    if (!type.isExisty(popup)) {
+	        this.openedPopup[options.popupName] = popup = this._open(useIEPostBridge, options.param,
+	            url, options.popupName, options.popupOptionStr);
+	    } else if (popup.closed) {
+	        this.openedPopup[options.popupName] = popup = this._open(useIEPostBridge, options.param,
+	            url, options.popupName, options.popupOptionStr);
+	    } else {
+	        if (options.useReload) {
+	            popup.location.replace(url);
+	        }
+	        popup.focus();
+	    }
+
+	    this.closeWithParentPopup[options.popupName] = options.closeWithParent;
+
+	    if (!popup || popup.closed || type.isUndefined(popup.closed)) {
+	        alert('please enable popup windows for this website');
+	    }
+
+	    if (options.param && options.method === 'POST' && !useIEPostBridge) {
+	        if (popup) {
+	            formElement.submit();
+	        }
+	        if (formElement.parentNode) {
+	            formElement.parentNode.removeChild(formElement);
+	        }
+	    }
+
+	    window.onunload = func.bind(this.closeAllPopup, this);
+	};
+
+	/**
+	 * Close the popup
+	 * @param {boolean} [skipBeforeUnload] - If true, the 'window.onunload' will be null and skip unload event.
+	 * @param {Window} [popup] - Window-context of popup for closing. If omit this, current window-context will be closed.
+	 */
+	Popup.prototype.close = function(skipBeforeUnload, popup) {
+	    var target = popup || window;
+	    skipBeforeUnload = type.isExisty(skipBeforeUnload) ? skipBeforeUnload : false;
+
+	    if (skipBeforeUnload) {
+	        window.onunload = null;
+	    }
+
+	    if (!target.closed) {
+	        target.opener = window.location.href;
+	        target.close();
+	    }
+	};
+
+	/**
+	 * Close all the popups in current window.
+	 * @param {boolean} closeWithParent - If true, popups having the closeWithParentPopup property as true will be closed.
+	 */
+	Popup.prototype.closeAllPopup = function(closeWithParent) {
+	    var hasArg = type.isExisty(closeWithParent);
+
+	    collection.forEachOwnProperties(this.openedPopup, function(popup, key) {
+	        if ((hasArg && this.closeWithParentPopup[key]) || !hasArg) {
+	            this.close(false, popup);
+	        }
+	    }, this);
+	};
+
+	/**
+	 * Activate(or focus) the popup of the given name.
+	 * @param {string} popupName - Name of popup for activation
+	 */
+	Popup.prototype.focus = function(popupName) {
+	    this.getPopupList(popupName).focus();
+	};
+
+	/**
+	 * Return an object made of parsing the query string.
+	 * @returns {Object} An object having some information of the query string.
+	 * @private
+	 */
+	Popup.prototype.parseQuery = function() {
+	    var param = {};
+	    var search, pair;
+
+	    search = window.location.search.substr(1);
+	    collection.forEachArray(search.split('&'), function(part) {
+	        pair = part.split('=');
+	        param[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
+	    });
+
+	    return param;
+	};
+
+	/**
+	 * Create a hidden form from the given arguments and return this form.
+	 * @param {string} action - URL for form transmission
+	 * @param {Object} [data] - Data for form transmission
+	 * @param {string} [method] - Method of transmission
+	 * @param {string} [target] - Target of transmission
+	 * @param {HTMLElement} [container] - Container element of form.
+	 * @returns {HTMLElement} Form element
+	 */
+	Popup.prototype.createForm = function(action, data, method, target, container) {
+	    var form = document.createElement('form'),
+	        input;
+
+	    container = container || document.body;
+
+	    form.method = method || 'POST';
+	    form.action = action || '';
+	    form.target = target || '';
+	    form.style.display = 'none';
+
+	    collection.forEachOwnProperties(data, function(value, key) {
+	        input = document.createElement('input');
+	        input.name = key;
+	        input.type = 'hidden';
+	        input.value = value;
+	        form.appendChild(input);
+	    });
+
+	    container.appendChild(form);
+
+	    return form;
+	};
+
+	/**********
+	 * private methods
+	 **********/
+
+	/**
+	 * Return an query string made by parsing the given object
+	 * @param {Object} obj - An object that has information for query string
+	 * @returns {string} - Query string
+	 * @private
+	 */
+	Popup.prototype._parameterize = function(obj) {
+	    var query = [];
+
+	    collection.forEachOwnProperties(obj, function(value, key) {
+	        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
+	    });
+
+	    return query.join('&');
+	};
+
+	/**
+	 * Open popup
+	 * @param {boolean} useIEPostBridge - A switch option whether to use alternative
+	 *                                  of tossing POST data to the popup window in IE11
+	 * @param {Object} param - A data for tossing to popup
+	 * @param {string} url - Popup url
+	 * @param {string} popupName - Popup name
+	 * @param {string} optionStr - Setting for popup, ex) 'width=640,height=320,scrollbars=yes'
+	 * @returns {Window} Window context of popup
+	 * @private
+	 */
+	Popup.prototype._open = function(useIEPostBridge, param, url, popupName, optionStr) {
+	    var popup;
+
+	    if (useIEPostBridge) {
+	        popup = window.open(this.postBridgeUrl, popupName, optionStr);
+	        setTimeout(function() {
+	            popup.redirect(url, param);
+	        }, 100);
+	    } else {
+	        popup = window.open(url, popupName, optionStr);
+	    }
+
+	    return popup;
+	};
+
+	module.exports = new Popup();
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module has a function for date format.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type.js, object.js
+	 */
+
+	'use strict';
+
+	var type = __webpack_require__(2);
+	var object = __webpack_require__(1);
+
+	var tokens = /[\\]*YYYY|[\\]*YY|[\\]*MMMM|[\\]*MMM|[\\]*MM|[\\]*M|[\\]*DD|[\\]*D|[\\]*HH|[\\]*H|[\\]*A/gi;
+	var MONTH_STR = [
+	    'Invalid month', 'January', 'February', 'March', 'April', 'May',
+	    'June', 'July', 'August', 'September', 'October', 'November', 'December'
+	];
+	var MONTH_DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+	var replaceMap = {
+	    M: function(date) {
+	        return Number(date.month);
+	    },
+	    MM: function(date) {
+	        var month = date.month;
+	        return (Number(month) < 10) ? '0' + month : month;
+	    },
+	    MMM: function(date) {
+	        return MONTH_STR[Number(date.month)].substr(0, 3);
+	    },
+	    MMMM: function(date) {
+	        return MONTH_STR[Number(date.month)];
+	    },
+	    D: function(date) {
+	        return Number(date.date);
+	    },
+	    d: function(date) {
+	        return replaceMap.D(date); // eslint-disable-line new-cap
+	    },
+	    DD: function(date) {
+	        var dayInMonth = date.date;
+	        return (Number(dayInMonth) < 10) ? '0' + dayInMonth : dayInMonth;
+	    },
+	    dd: function(date) {
+	        return replaceMap.DD(date); // eslint-disable-line new-cap
+	    },
+	    YY: function(date) {
+	        return Number(date.year) % 100;
+	    },
+	    yy: function(date) {
+	        return replaceMap.YY(date); // eslint-disable-line new-cap
+	    },
+	    YYYY: function(date) {
+	        var prefix = '20',
+	            year = date.year;
+	        if (year > 69 && year < 100) {
+	            prefix = '19';
+	        }
+	        return (Number(year) < 100) ? prefix + String(year) : year;
+	    },
+	    yyyy: function(date) {
+	        return replaceMap.YYYY(date); // eslint-disable-line new-cap
+	    },
+	    A: function(date) {
+	        return date.meridiem;
+	    },
+	    a: function(date) {
+	        return date.meridiem;
+	    },
+	    hh: function(date) {
+	        var hour = date.hour;
+	        return (Number(hour) < 10) ? '0' + hour : hour;
+	    },
+	    HH: function(date) {
+	        return replaceMap.hh(date);
+	    },
+	    h: function(date) {
+	        return String(Number(date.hour));
+	    },
+	    H: function(date) {
+	        return replaceMap.h(date);
+	    },
+	    m: function(date) {
+	        return String(Number(date.minute));
+	    },
+	    mm: function(date) {
+	        var minute = date.minute;
+	        return (Number(minute) < 10) ? '0' + minute : minute;
+	    }
+	};
+
+	/**
+	 * Check whether the given variables are valid date or not.
+	 * @param {number} year - Year
+	 * @param {number} month - Month
+	 * @param {number} date - Day in month.
+	 * @returns {boolean} Is valid?
+	 * @private
+	 */
+	function isValidDate(year, month, date) { // eslint-disable-line complexity
+	    var isValidYear, isValidMonth, isValid, lastDayInMonth;
+
+	    year = Number(year);
+	    month = Number(month);
+	    date = Number(date);
+
+	    isValidYear = (year > -1 && year < 100) || (year > 1969) && (year < 2070);
+	    isValidMonth = (month > 0) && (month < 13);
+
+	    if (!isValidYear || !isValidMonth) {
+	        return false;
+	    }
+
+	    lastDayInMonth = MONTH_DAYS[month];
+	    if (month === 2 && year % 4 === 0) {
+	        if (year % 100 !== 0 || year % 400 === 0) {
+	            lastDayInMonth = 29;
+	        }
+	    }
+
+	    isValid = (date > 0) && (date <= lastDayInMonth);
+	    return isValid;
+	}
+
+	/**
+	 * Return a string that transformed from the given form and date.
+	 * @param {string} form - Date form
+	 * @param {Date|Object} date - Date object
+	 * @param {{meridiemSet: {AM: string, PM: string}}} option - Option
+	 * @returns {boolean|string} A transformed string or false.
+	 * @memberof tui.util
+	 * @example
+	 *  // key             | Shorthand
+	 *  // --------------- |-----------------------
+	 *  // years           | YY / YYYY / yy / yyyy
+	 *  // months(n)       | M / MM
+	 *  // months(str)     | MMM / MMMM
+	 *  // days            | D / DD / d / dd
+	 *  // hours           | H / HH / h / hh
+	 *  // minutes         | m / mm
+	 *  // meridiem(AM,PM) | A / a
+	 *
+	 *  var dateStr1 = formatDate('yyyy-MM-dd', {
+	 *      year: 2014,
+	 *      month: 12,
+	 *      date: 12
+	 *  });
+	 *  alert(dateStr1); // '2014-12-12'
+	 *
+	 *  var dateStr2 = formatDate('MMM DD YYYY HH:mm', {
+	 *      year: 1999,
+	 *      month: 9,
+	 *      date: 9,
+	 *      hour: 0,
+	 *      minute: 2
+	 *  })
+	 *  alert(dateStr2); // 'Sep 09 1999 00:02'
+	 *
+	 *  var dt = new Date(2010, 2, 13),
+	 *      dateStr3 = formatDate('yyyy년 M월 dd일', dt);
+	 *
+	 *  alert(dateStr3); // '2010년 3월 13일'
+	 *
+	 *  var option4 = {
+	 *      meridiemSet: {
+	 *          AM: '오전',
+	 *          PM: '오후'
+	 *      }
+	 *  };
+	 *  var date4 = {year: 1999, month: 9, date: 9, hour: 13, minute: 2};
+	 *  var dateStr4 = formatDate('yyyy-MM-dd A hh:mm', date4, option4));
+	 *
+	 *  alert(dateStr4); // '1999-09-09 오후 01:02'
+	 */
+	function formatDate(form, date, option) { // eslint-disable-line complexity
+	    var meridiem, nDate, resultStr;
+
+	    if (type.isDate(date)) {
+	        nDate = {
+	            year: date.getFullYear(),
+	            month: date.getMonth() + 1,
+	            date: date.getDate(),
+	            hour: date.getHours(),
+	            minute: date.getMinutes()
+	        };
+	    } else {
+	        nDate = {
+	            year: date.year,
+	            month: date.month,
+	            date: date.date,
+	            hour: date.hour,
+	            minute: date.minute
+	        };
+	    }
+
+	    if (!isValidDate(nDate.year, nDate.month, nDate.date)) {
+	        return false;
+	    }
+
+	    nDate.meridiem = '';
+	    if (/([^\\]|^)[aA]\b/.test(form)) {
+	        meridiem = (nDate.hour > 11) ?
+	            object.pick(option, 'meridiemSet', 'PM') || 'PM'
+	            : object.pick(option, 'meridiemSet', 'AM') || 'AM';
+	        if (nDate.hour > 12) { //See the clock system: https://en.wikipedia.org/wiki/12-hour_clock
+	            nDate.hour %= 12;
+	        }
+	        if (nDate.hour === 0) {
+	            nDate.hour = 12;
+	        }
+	        nDate.meridiem = meridiem;
+	    }
+
+	    resultStr = form.replace(tokens, function(key) {
+	        if (key.indexOf('\\') > -1) { // escape character
+	            return key.replace(/\\/, '');
+	        }
+	        return replaceMap[key](nDate) || '';
+	    });
+	    return resultStr;
+	}
+
+	module.exports = formatDate;
+
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview
+	 *  This module provides a function to make a constructor
+	 * that can inherit from the other constructors like the CLASS easily.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependencies inheritance.js, object.js
+	 */
+
+	'use strict';
+
+	var inherit = __webpack_require__(6).inherit;
+	var extend = __webpack_require__(1).extend;
+
+	/**
+	 * Help a constructor to be defined and to inherit from the other constructors
+	 * @param {*} [parent] Parent constructor
+	 * @param {Object} props Members of constructor
+	 *  @param {Function} props.init Initialization method
+	 *  @param {Object} [props.static] Static members of constructor
+	 * @returns {*} Constructor
+	 * @memberof tui.util
+	 * @example
+	 *  var Parent = tui.util.defineClass({
+	 *      init: function() {
+	 *          this.name = 'made by def';
+	 *      },
+	 *      method: function() {
+	 *          //..can do something with this
+	 *      },
+	 *      static: {
+	 *          staticMethod: function() {
+	 *               //..do something
+	 *          }
+	 *      }
+	 *  });
+	 *
+	 *  var Child = tui.util.defineClass(Parent, {
+	 *      method2: function() {}
+	 *  });
+	 *
+	 *  Parent.staticMethod();
+	 *
+	 *  var parentInstance = new Parent();
+	 *  console.log(parentInstance.name); //made by def
+	 *  parentInstance.staticMethod(); // Error
+	 *
+	 *  var childInstance = new Child();
+	 *  childInstance.method();
+	 *  childInstance.method2();
+	 */
+	function defineClass(parent, props) {
+	    var obj;
+
+	    if (!props) {
+	        props = parent;
+	        parent = null;
+	    }
+
+	    obj = props.init || function() {};
+
+	    if (parent) {
+	        inherit(obj, parent);
+	    }
+
+	    if (props.hasOwnProperty('static')) {
+	        extend(obj, props['static']);
+	        delete props['static'];
+	    }
+
+	    extend(obj.prototype, props);
+
+	    return obj;
+	}
+
+	module.exports = defineClass;
+
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview Define module
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javscript@nhnent.com>
+	 * @dependency type.js, defineNamespace.js
+	 */
+	'use strict';
+
+	var defineNamespace = __webpack_require__(14);
+	var type = __webpack_require__(2);
+
+	var INITIALIZATION_METHOD_NAME = 'initialize';
+
+	/**
+	 * Define module
+	 * @param {string} namespace - Namespace of module
+	 * @param {Object} moduleDefinition - Object literal for module
+	 * @returns {Object} Defined module
+	 * @memberof tui.util
+	 * @example
+	 *     var myModule = tui.util.defineModule('modules.myModule', {
+	 *          name: 'john',
+	 *          message: '',
+	 *          initialize: function() {
+	 *              this.message = 'hello world';
+	 *          },
+	 *          getMessage: function() {
+	 *              return this.name + ': ' + this.message
+	 *          }
+	 *     });
+	 *
+	 *     console.log(myModule.getMessage());  // 'john: hello world';
+	 *     console.log(window.modules.myModule.getMessage());   // 'john: hello world';
+	 */
+	function defineModule(namespace, moduleDefinition) {
+	    var base = moduleDefinition || {};
+
+	    if (type.isFunction(base[INITIALIZATION_METHOD_NAME])) {
+	        base[INITIALIZATION_METHOD_NAME]();
+	    }
+
+	    return defineNamespace(namespace, base);
+	}
+
+	module.exports = defineModule;
+
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview Define namespace
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency object.js, collection.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var object = __webpack_require__(1);
+
+	/**
+	 * Define namespace
+	 * @param {string} namespace - Namespace (ex- 'foo.bar.baz')
+	 * @param {(object|function)} props - A set of modules or one module
+	 * @param {boolean} [isOverride] - Override the props to the namespace.<br>
+	 *                                  (It removes previous properties of this namespace)
+	 * @returns {(object|function)} Defined namespace
+	 * @memberof tui.util
+	 * @example
+	 * var neComp = tui.util.defineNamespace('ne.component');
+	 * neComp.listMenu = defineClass({
+	 *      init: function() {
+	 *          // code
+	 *      }
+	 * });
+	 */
+	function defineNamespace(namespace, props, isOverride) {
+	    var names, result, prevLast, last;
+
+	    names = namespace.split('.');
+	    names.unshift(window);
+
+	    result = collection.reduce(names, function(obj, name) {
+	        obj[name] = obj[name] || {};
+	        return obj[name];
+	    });
+
+	    if (isOverride) {
+	        last = names.pop();
+	        prevLast = object.pick.apply(null, names);
+	        result = prevLast[last] = props;
+	    } else {
+	        object.extend(result, props);
+	    }
+
+	    return result;
+	}
+
+	module.exports = defineNamespace;
+
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview
+	 *  This module provides some functions for custom events.<br>
+	 *  And it is implemented in the observer design pattern.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type.js, collection.js object.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+	var object = __webpack_require__(1);
+
+	var R_EVENTNAME_SPLIT = /\s+/g;
+
+	/**
+	 * A unit of event handler item.
+	 * @ignore
+	 * @typedef {object} HandlerItem
+	 * @property {function} fn - event handler
+	 * @property {object} ctx - context of event handler
+	 */
+
+	/**
+	 * @class
+	 * @memberof tui.util
+	 */
+	function CustomEvents() {
+	    /**
+	     * @type {HandlerItem[]}
+	     */
+	    this.events = null;
+
+	    /**
+	     * only for checking specific context event was binded
+	     * @type {object[]}
+	     */
+	    this.contexts = null;
+	}
+
+	/**
+	 * Mixin custom events feature to specific constructor
+	 * @param {function} func - constructor
+	 * @example
+	 *  function Model() {
+	 *      this.name = '';
+	 *  }
+	 *  tui.util.CustomEvents.mixin(Model);
+	 *
+	 *  var model = new Model();
+	 *  model.on('change', function() { this.name = 'model'; }, this);
+	 *
+	 *  model.fire('change');
+	 *  alert(model.name); // 'model';
+	 */
+	CustomEvents.mixin = function(func) {
+	    object.extend(func.prototype, CustomEvents.prototype);
+	};
+
+	/**
+	 * Get HandlerItem object
+	 * @param {function} handler - handler function
+	 * @param {object} [context] - context for handler
+	 * @returns {HandlerItem} HandlerItem object
+	 * @private
+	 */
+	CustomEvents.prototype._getHandlerItem = function(handler, context) {
+	    var item = {handler: handler};
+
+	    if (context) {
+	        item.context = context;
+	    }
+
+	    return item;
+	};
+
+	/**
+	 * Get event object safely
+	 * @param {string} [eventName] - create sub event map if not exist.
+	 * @returns {(object|array)} event object. if you supplied `eventName`
+	 *  parameter then make new array and return it
+	 * @private
+	 */
+	CustomEvents.prototype._safeEvent = function(eventName) {
+	    var events = this.events;
+	    var byName;
+
+	    if (!events) {
+	        events = this.events = {};
+	    }
+
+	    if (eventName) {
+	        byName = events[eventName];
+
+	        if (!byName) {
+	            byName = [];
+	            events[eventName] = byName;
+	        }
+
+	        events = byName;
+	    }
+
+	    return events;
+	};
+
+	/**
+	 * Get context array safely
+	 * @returns {array} context array
+	 * @private
+	 */
+	CustomEvents.prototype._safeContext = function() {
+	    var context = this.contexts;
+
+	    if (!context) {
+	        context = this.contexts = [];
+	    }
+
+	    return context;
+	};
+
+	/**
+	 * Get index of context
+	 * @param {object} ctx - context that used for bind custom event
+	 * @returns {number} index of context
+	 * @private
+	 */
+	CustomEvents.prototype._indexOfContext = function(ctx) {
+	    var context = this._safeContext();
+	    var index = 0;
+
+	    while (context[index]) {
+	        if (ctx === context[index][0]) {
+	            return index;
+	        }
+
+	        index += 1;
+	    }
+
+	    return -1;
+	};
+
+	/**
+	 * Memorize supplied context for recognize supplied object is context or
+	 *  name: handler pair object when off()
+	 * @param {object} ctx - context object to memorize
+	 * @private
+	 */
+	CustomEvents.prototype._memorizeContext = function(ctx) {
+	    var context, index;
+
+	    if (!type.isExisty(ctx)) {
+	        return;
+	    }
+
+	    context = this._safeContext();
+	    index = this._indexOfContext(ctx);
+
+	    if (index > -1) {
+	        context[index][1] += 1;
+	    } else {
+	        context.push([ctx, 1]);
+	    }
+	};
+
+	/**
+	 * Forget supplied context object
+	 * @param {object} ctx - context object to forget
+	 * @private
+	 */
+	CustomEvents.prototype._forgetContext = function(ctx) {
+	    var context, contextIndex;
+
+	    if (!type.isExisty(ctx)) {
+	        return;
+	    }
+
+	    context = this._safeContext();
+	    contextIndex = this._indexOfContext(ctx);
+
+	    if (contextIndex > -1) {
+	        context[contextIndex][1] -= 1;
+
+	        if (context[contextIndex][1] <= 0) {
+	            context.splice(contextIndex, 1);
+	        }
+	    }
+	};
+
+	/**
+	 * Bind event handler
+	 * @param {(string|{name:string, handler:function})} eventName - custom
+	 *  event name or an object {eventName: handler}
+	 * @param {(function|object)} [handler] - handler function or context
+	 * @param {object} [context] - context for binding
+	 * @private
+	 */
+	CustomEvents.prototype._bindEvent = function(eventName, handler, context) {
+	    var events = this._safeEvent(eventName);
+	    this._memorizeContext(context);
+	    events.push(this._getHandlerItem(handler, context));
+	};
+
+	/**
+	 * Bind event handlers
+	 * @param {(string|{name:string, handler:function})} eventName - custom
+	 *  event name or an object {eventName: handler}
+	 * @param {(function|object)} [handler] - handler function or context
+	 * @param {object} [context] - context for binding
+	 * @example
+	 *  // 1. Basic
+	 *  ustomEvent.on('onload', handler);
+	 *
+	 *  // 2. With context
+	 *  customEvent.on('onload', handler, myObj);
+	 *
+	 *  // 3. Bind by object that name, handler pairs
+	 *  customEvent.on({
+	 *    'play': handler,
+	 *    'pause': handler2
+	 *  });
+	 *
+	 *  // 4. Bind by object that name, handler pairs with context object
+	 *  customEvent.on({
+	 *    'play': handler
+	 *  }, myObj);
+	 */
+	CustomEvents.prototype.on = function(eventName, handler, context) {
+	    var self = this;
+
+	    if (type.isString(eventName)) {
+	        // [syntax 1, 2]
+	        eventName = eventName.split(R_EVENTNAME_SPLIT);
+	        collection.forEach(eventName, function(name) {
+	            self._bindEvent(name, handler, context);
+	        });
+	    } else if (type.isObject(eventName)) {
+	        // [syntax 3, 4]
+	        context = handler;
+	        collection.forEach(eventName, function(func, name) {
+	            self.on(name, func, context);
+	        });
+	    }
+	};
+
+	/**
+	 * Bind one-shot event handlers
+	 * @param {(string|{name:string,handler:function})} eventName - custom
+	 *  event name or an object {eventName: handler}
+	 * @param {function|object} [handler] - handler function or context
+	 * @param {object} [context] - context for binding
+	 */
+	CustomEvents.prototype.once = function(eventName, handler, context) {
+	    var self = this;
+
+	    if (type.isObject(eventName)) {
+	        context = handler;
+	        collection.forEach(eventName, function(func, name) {
+	            self.once(name, func, context);
+	        });
+	        return;
+	    }
+
+	    function onceHandler() { // eslint-disable-line require-jsdoc
+	        handler.apply(context, arguments);
+	        self.off(eventName, onceHandler, context);
+	    }
+
+	    this.on(eventName, onceHandler, context);
+	};
+
+	/**
+	 * Splice supplied array by callback result
+	 * @param {array} arr - array to splice
+	 * @param {function} predicate - function return boolean
+	 * @private
+	 */
+	CustomEvents.prototype._spliceMatches = function(arr, predicate) {
+	    var i = 0;
+	    var len;
+
+	    if (!type.isArray(arr)) {
+	        return;
+	    }
+
+	    for (len = arr.length; i < len; i += 1) {
+	        if (predicate(arr[i]) === true) {
+	            arr.splice(i, 1);
+	            len -= 1;
+	            i -= 1;
+	        }
+	    }
+	};
+
+	/**
+	 * Get matcher for unbind specific handler events
+	 * @param {function} handler - handler function
+	 * @returns {function} handler matcher
+	 * @private
+	 */
+	CustomEvents.prototype._matchHandler = function(handler) {
+	    var self = this;
+
+	    return function(item) {
+	        var needRemove = handler === item.handler;
+
+	        if (needRemove) {
+	            self._forgetContext(item.context);
+	        }
+
+	        return needRemove;
+	    };
+	};
+
+	/**
+	 * Get matcher for unbind specific context events
+	 * @param {object} context - context
+	 * @returns {function} object matcher
+	 * @private
+	 */
+	CustomEvents.prototype._matchContext = function(context) {
+	    var self = this;
+
+	    return function(item) {
+	        var needRemove = context === item.context;
+
+	        if (needRemove) {
+	            self._forgetContext(item.context);
+	        }
+
+	        return needRemove;
+	    };
+	};
+
+	/**
+	 * Get matcher for unbind specific hander, context pair events
+	 * @param {function} handler - handler function
+	 * @param {object} context - context
+	 * @returns {function} handler, context matcher
+	 * @private
+	 */
+	CustomEvents.prototype._matchHandlerAndContext = function(handler, context) {
+	    var self = this;
+
+	    return function(item) {
+	        var matchHandler = (handler === item.handler);
+	        var matchContext = (context === item.context);
+	        var needRemove = (matchHandler && matchContext);
+
+	        if (needRemove) {
+	            self._forgetContext(item.context);
+	        }
+
+	        return needRemove;
+	    };
+	};
+
+	/**
+	 * Unbind event by event name
+	 * @param {string} eventName - custom event name to unbind
+	 * @param {function} [handler] - handler function
+	 * @private
+	 */
+	CustomEvents.prototype._offByEventName = function(eventName, handler) {
+	    var self = this;
+	    var forEach = collection.forEachArray;
+	    var andByHandler = type.isFunction(handler);
+	    var matchHandler = self._matchHandler(handler);
+
+	    eventName = eventName.split(R_EVENTNAME_SPLIT);
+
+	    forEach(eventName, function(name) {
+	        var handlerItems = self._safeEvent(name);
+
+	        if (andByHandler) {
+	            self._spliceMatches(handlerItems, matchHandler);
+	        } else {
+	            forEach(handlerItems, function(item) {
+	                self._forgetContext(item.context);
+	            });
+
+	            self.events[name] = [];
+	        }
+	    });
+	};
+
+	/**
+	 * Unbind event by handler function
+	 * @param {function} handler - handler function
+	 * @private
+	 */
+	CustomEvents.prototype._offByHandler = function(handler) {
+	    var self = this;
+	    var matchHandler = this._matchHandler(handler);
+
+	    collection.forEach(this._safeEvent(), function(handlerItems) {
+	        self._spliceMatches(handlerItems, matchHandler);
+	    });
+	};
+
+	/**
+	 * Unbind event by object(name: handler pair object or context object)
+	 * @param {object} obj - context or {name: handler} pair object
+	 * @param {function} handler - handler function
+	 * @private
+	 */
+	CustomEvents.prototype._offByObject = function(obj, handler) {
+	    var self = this;
+	    var matchFunc;
+
+	    if (this._indexOfContext(obj) < 0) {
+	        collection.forEach(obj, function(func, name) {
+	            self.off(name, func);
+	        });
+	    } else if (type.isString(handler)) {
+	        matchFunc = this._matchContext(obj);
+
+	        self._spliceMatches(this._safeEvent(handler), matchFunc);
+	    } else if (type.isFunction(handler)) {
+	        matchFunc = this._matchHandlerAndContext(handler, obj);
+
+	        collection.forEach(this._safeEvent(), function(handlerItems) {
+	            self._spliceMatches(handlerItems, matchFunc);
+	        });
+	    } else {
+	        matchFunc = this._matchContext(obj);
+
+	        collection.forEach(this._safeEvent(), function(handlerItems) {
+	            self._spliceMatches(handlerItems, matchFunc);
+	        });
+	    }
+	};
+
+	/**
+	 * Unbind custom events
+	 * @param {(string|object|function)} eventName - event name or context or
+	 *  {name: handler} pair object or handler function
+	 * @param {(function)} handler - handler function
+	 * @example
+	 * // 1. off by event name
+	 * customEvent.off('onload');
+	 *
+	 * // 2. off by event name and handler
+	 * customEvent.off('play', handler);
+	 *
+	 * // 3. off by handler
+	 * customEvent.off(handler);
+	 *
+	 * // 4. off by context
+	 * customEvent.off(myObj);
+	 *
+	 * // 5. off by context and handler
+	 * customEvent.off(myObj, handler);
+	 *
+	 * // 6. off by context and event name
+	 * customEvent.off(myObj, 'onload');
+	 *
+	 * // 7. off by an Object.<string, function> that is {eventName: handler}
+	 * customEvent.off({
+	 *   'play': handler,
+	 *   'pause': handler2
+	 * });
+	 *
+	 * // 8. off the all events
+	 * customEvent.off();
+	 */
+	CustomEvents.prototype.off = function(eventName, handler) {
+	    if (type.isString(eventName)) {
+	        // [syntax 1, 2]
+	        this._offByEventName(eventName, handler);
+	    } else if (!arguments.length) {
+	        // [syntax 8]
+	        this.events = {};
+	        this.contexts = [];
+	    } else if (type.isFunction(eventName)) {
+	        // [syntax 3]
+	        this._offByHandler(eventName);
+	    } else if (type.isObject(eventName)) {
+	        // [syntax 4, 5, 6]
+	        this._offByObject(eventName, handler);
+	    }
+	};
+
+	/**
+	 * Fire custom event
+	 * @param {string} eventName - name of custom event
+	 */
+	CustomEvents.prototype.fire = function(eventName) {  // eslint-disable-line
+	    this.invoke.apply(this, arguments);
+	};
+
+	/**
+	 * Fire a event and returns the result of operation 'boolean AND' with all
+	 *  listener's results.
+	 *
+	 * So, It is different from {@link CustomEvents#fire}.
+	 *
+	 * In service code, use this as a before event in component level usually
+	 *  for notifying that the event is cancelable.
+	 * @param {string} eventName - Custom event name
+	 * @param {...*} data - Data for event
+	 * @returns {boolean} The result of operation 'boolean AND'
+	 * @example
+	 *  if (this.invoke('beforeZoom')) {    // check the result of 'beforeZoom'
+	 *      // if true,
+	 *      // doSomething
+	 *  }
+	 *
+	 *  // In service code,
+	 *  map.on({
+	 *      'beforeZoom': function() {
+	 *          // It should cancel the 'zoom' event by some conditions.
+	 *          if (that.disabled && this.getState()) {
+	 *              return false;
+	 *          }
+	 *          return true;
+	 *      }
+	 *  });
+	 */
+	CustomEvents.prototype.invoke = function(eventName) {
+	    var events, args, index, item;
+
+	    if (!this.hasListener(eventName)) {
+	        return true;
+	    }
+
+	    events = this._safeEvent(eventName);
+	    args = Array.prototype.slice.call(arguments, 1);
+	    index = 0;
+
+	    while (events[index]) {
+	        item = events[index];
+
+	        if (item.handler.apply(item.context, args) === false) {
+	            return false;
+	        }
+
+	        index += 1;
+	    }
+
+	    return true;
+	};
+
+	/**
+	 * Return whether at least one of the handlers is registered in the given
+	 *  event name.
+	 * @param {string} eventName - Custom event name
+	 * @returns {boolean} Is there at least one handler in event name?
+	 */
+	CustomEvents.prototype.hasListener = function(eventName) {
+	    return this.getListenerLength(eventName) > 0;
+	};
+
+	/**
+	 * Return a count of events registered.
+	 * @param {string} eventName - Custom event name
+	 * @returns {number} number of event
+	 */
+	CustomEvents.prototype.getListenerLength = function(eventName) {
+	    var events = this._safeEvent(eventName);
+	    return events.length;
+	};
+
+	module.exports = CustomEvents;
+
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module provides a Enum Constructor.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type, collection.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+
+	/**
+	 * Check whether the defineProperty() method is supported.
+	 * @type {boolean}
+	 * @ignore
+	 */
+	var isSupportDefinedProperty = (function() {
+	    try {
+	        Object.defineProperty({}, 'x', {});
+	        return true;
+	    } catch (e) {
+	        return false;
+	    }
+	})();
+
+	/**
+	 * A unique value of a constant.
+	 * @type {number}
+	 * @ignore
+	 */
+	var enumValue = 0;
+
+	/**
+	 * Make a constant-list that has unique values.<br>
+	 * In modern browsers (except IE8 and lower),<br>
+	 *  a value defined once can not be changed.
+	 *
+	 * @param {...string|string[]} itemList Constant-list (An array of string is available)
+	 * @class
+	 * @memberof tui.util
+	 * @example
+	 *  //create
+	 *  var MYENUM = new tui.util.Enum('TYPE1', 'TYPE2');
+	 *  var MYENUM2 = new tui.util.Enum(['TYPE1', 'TYPE2']);
+	 *
+	 *  //usage
+	 *  if (value === MYENUM.TYPE1) {
+	 *       ....
+	 *  }
+	 *
+	 *  //add (If a duplicate name is inputted, will be disregarded.)
+	 *  MYENUM.set('TYPE3', 'TYPE4');
+	 *
+	 *  //get name of a constant by a value
+	 *  MYENUM.getName(MYENUM.TYPE1); // 'TYPE1'
+	 *
+	 *  // In modern browsers (except IE8 and lower), a value can not be changed in constants.
+	 *  var originalValue = MYENUM.TYPE1;
+	 *  MYENUM.TYPE1 = 1234; // maybe TypeError
+	 *  MYENUM.TYPE1 === originalValue; // true
+	 *
+	 **/
+	function Enum(itemList) {
+	    if (itemList) {
+	        this.set.apply(this, arguments);
+	    }
+	}
+
+	/**
+	 * Define a constants-list
+	 * @param {...string|string[]} itemList Constant-list (An array of string is available)
+	 */
+	Enum.prototype.set = function(itemList) {
+	    var self = this;
+
+	    if (!type.isArray(itemList)) {
+	        itemList = collection.toArray(arguments);
+	    }
+
+	    collection.forEach(itemList, function itemListIteratee(item) {
+	        self._addItem(item);
+	    });
+	};
+
+	/**
+	 * Return a key of the constant.
+	 * @param {number} value A value of the constant.
+	 * @returns {string|undefined} Key of the constant.
+	 */
+	Enum.prototype.getName = function(value) {
+	    var self = this;
+	    var foundedKey;
+
+	    collection.forEach(this, function(itemValue, key) { // eslint-disable-line consistent-return
+	        if (self._isEnumItem(key) && value === itemValue) {
+	            foundedKey = key;
+	            return false;
+	        }
+	    });
+
+	    return foundedKey;
+	};
+
+	/**
+	 * Create a constant.
+	 * @private
+	 * @param {string} name Constant name. (It will be a key of a constant)
+	 */
+	Enum.prototype._addItem = function(name) {
+	    var value;
+
+	    if (!this.hasOwnProperty(name)) {
+	        value = this._makeEnumValue();
+
+	        if (isSupportDefinedProperty) {
+	            Object.defineProperty(this, name, {
+	                enumerable: true,
+	                configurable: false,
+	                writable: false,
+	                value: value
+	            });
+	        } else {
+	            this[name] = value;
+	        }
+	    }
+	};
+
+	/**
+	 * Return a unique value for assigning to a constant.
+	 * @private
+	 * @returns {number} A unique value
+	 */
+	Enum.prototype._makeEnumValue = function() {
+	    var value;
+
+	    value = enumValue;
+	    enumValue += 1;
+
+	    return value;
+	};
+
+	/**
+	 * Return whether a constant from the given key is in instance or not.
+	 * @param {string} key - A constant key
+	 * @returns {boolean} Result
+	 * @private
+	 */
+	Enum.prototype._isEnumItem = function(key) {
+	    return type.isNumber(this[key]);
+	};
+
+	module.exports = Enum;
+
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview
+	 *  Implements the ExMap (Extended Map) object.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency Map.js, collection.js
+	 */
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var Map = __webpack_require__(18);
+
+	// Caching tui.util for performance enhancing
+	var mapAPIsForRead = ['get', 'has', 'forEach', 'keys', 'values', 'entries'];
+	var mapAPIsForDelete = ['delete', 'clear'];
+
+	/**
+	 * The ExMap object is Extended Version of the tui.util.Map object.<br>
+	 * and added some useful feature to make it easy to manage the Map object.
+	 * @constructor
+	 * @param {Array} initData - Array of key-value pairs (2-element Arrays).
+	 *      Each key-value pair will be added to the new Map
+	 * @memberof tui.util
+	 */
+	function ExMap(initData) {
+	    this._map = new Map(initData);
+	    this.size = this._map.size;
+	}
+
+	collection.forEachArray(mapAPIsForRead, function(name) {
+	    ExMap.prototype[name] = function() {
+	        return this._map[name].apply(this._map, arguments);
+	    };
+	});
+
+	collection.forEachArray(mapAPIsForDelete, function(name) {
+	    ExMap.prototype[name] = function() {
+	        var result = this._map[name].apply(this._map, arguments);
+	        this.size = this._map.size;
+	        return result;
+	    };
+	});
+
+	ExMap.prototype.set = function() {
+	    this._map.set.apply(this._map, arguments);
+	    this.size = this._map.size;
+	    return this;
+	};
+
+	/**
+	 * Sets all of the key-value pairs in the specified object to the Map object.
+	 * @param  {Object} object - Plain object that has a key-value pair
+	 */
+	ExMap.prototype.setObject = function(object) {
+	    collection.forEachOwnProperties(object, function(value, key) {
+	        this.set(key, value);
+	    }, this);
+	};
+
+	/**
+	 * Removes the elements associated with keys in the specified array.
+	 * @param  {Array} keys - Array that contains keys of the element to remove
+	 */
+	ExMap.prototype.deleteByKeys = function(keys) {
+	    collection.forEachArray(keys, function(key) {
+	        this['delete'](key);
+	    }, this);
+	};
+
+	/**
+	 * Sets all of the key-value pairs in the specified Map object to this Map object.
+	 * @param  {Map} map - Map object to be merged into this Map object
+	 */
+	ExMap.prototype.merge = function(map) {
+	    map.forEach(function(value, key) {
+	        this.set(key, value);
+	    }, this);
+	};
+
+	/**
+	 * Looks through each key-value pair in the map and returns the new ExMap object of
+	 * all key-value pairs that pass a truth test implemented by the provided function.
+	 * @param  {function} predicate - Function to test each key-value pair of the Map object.<br>
+	 *      Invoked with arguments (value, key). Return true to keep the element, false otherwise.
+	 * @returns {ExMap} A new ExMap object
+	 */
+	ExMap.prototype.filter = function(predicate) {
+	    var filtered = new ExMap();
+
+	    this.forEach(function(value, key) {
+	        if (predicate(value, key)) {
+	            filtered.set(key, value);
+	        }
+	    });
+
+	    return filtered;
+	};
+
+	module.exports = ExMap;
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	
+	/**
+	 * @fileoverview
+	 *  Implements the Map object.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type.js, collection.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+	var array = __webpack_require__(3);
+	var browser = __webpack_require__(9);
+	var func = __webpack_require__(5);
+
+	/**
+	 * Using undefined for a key can be ambiguous if there's deleted item in the array,<br>
+	 * which is also undefined when accessed by index.<br>
+	 * So use this unique object as an undefined key to distinguish it from deleted keys.
+	 * @private
+	 * @constant
+	 */
+	var _KEY_FOR_UNDEFINED = {};
+
+	/**
+	 * For using NaN as a key, use this unique object as a NaN key.<br>
+	 * This makes it easier and faster to compare an object with each keys in the array<br>
+	 * through no exceptional comapring for NaN.
+	 * @private
+	 * @constant
+	 */
+	var _KEY_FOR_NAN = {};
+
+	/**
+	 * Constructor of MapIterator<br>
+	 * Creates iterator object with new keyword.
+	 * @constructor
+	 * @param  {Array} keys - The array of keys in the map
+	 * @param  {function} valueGetter - Function that returns certain value,
+	 *      taking key and keyIndex as arguments.
+	 * @ignore
+	 */
+	function MapIterator(keys, valueGetter) {
+	    this._keys = keys;
+	    this._valueGetter = valueGetter;
+	    this._length = this._keys.length;
+	    this._index = -1;
+	    this._done = false;
+	}
+
+	/**
+	 * Implementation of Iterator protocol.
+	 * @returns {{done: boolean, value: *}} Object that contains done(boolean) and value.
+	 */
+	MapIterator.prototype.next = function() {
+	    var data = {};
+	    do {
+	        this._index += 1;
+	    } while (type.isUndefined(this._keys[this._index]) && this._index < this._length);
+
+	    if (this._index >= this._length) {
+	        data.done = true;
+	    } else {
+	        data.done = false;
+	        data.value = this._valueGetter(this._keys[this._index], this._index);
+	    }
+	    return data;
+	};
+
+	/**
+	 * The Map object implements the ES6 Map specification as closely as possible.<br>
+	 * For using objects and primitive values as keys, this object uses array internally.<br>
+	 * So if the key is not a string, get(), set(), has(), delete() will operates in O(n),<br>
+	 * and it can cause performance issues with a large dataset.
+	 *
+	 * Features listed below are not supported. (can't be implented without native support)
+	 * - Map object is iterable<br>
+	 * - Iterable object can be used as an argument of constructor
+	 *
+	 * If the browser supports full implementation of ES6 Map specification, native Map obejct
+	 * will be used internally.
+	 * @class
+	 * @param  {Array} initData - Array of key-value pairs (2-element Arrays).
+	 *      Each key-value pair will be added to the new Map
+	 * @memberof tui.util
+	 */
+	function Map(initData) {
+	    this._valuesForString = {};
+	    this._valuesForIndex = {};
+	    this._keys = [];
+
+	    if (initData) {
+	        this._setInitData(initData);
+	    }
+
+	    this.size = 0;
+	}
+
+	/* eslint-disable no-extend-native */
+	/**
+	 * Add all elements in the initData to the Map object.
+	 * @private
+	 * @param  {Array} initData - Array of key-value pairs to add to the Map object
+	 */
+	Map.prototype._setInitData = function(initData) {
+	    if (!type.isArray(initData)) {
+	        throw new Error('Only Array is supported.');
+	    }
+	    collection.forEachArray(initData, function(pair) {
+	        this.set(pair[0], pair[1]);
+	    }, this);
+	};
+
+	/**
+	 * Returns true if the specified value is NaN.<br>
+	 * For unsing NaN as a key, use this method to test equality of NaN<br>
+	 * because === operator doesn't work for NaN.
+	 * @private
+	 * @param {*} value - Any object to be tested
+	 * @returns {boolean} True if value is NaN, false otherwise.
+	 */
+	Map.prototype._isNaN = function(value) {
+	    return typeof value === 'number' && value !== value; // eslint-disable-line no-self-compare
+	};
+
+	/**
+	 * Returns the index of the specified key.
+	 * @private
+	 * @param  {*} key - The key object to search for.
+	 * @returns {number} The index of the specified key
+	 */
+	Map.prototype._getKeyIndex = function(key) {
+	    var result = -1;
+	    var value;
+
+	    if (type.isString(key)) {
+	        value = this._valuesForString[key];
+	        if (value) {
+	            result = value.keyIndex;
+	        }
+	    } else {
+	        result = array.inArray(key, this._keys);
+	    }
+	    return result;
+	};
+
+	/**
+	 * Returns the original key of the specified key.
+	 * @private
+	 * @param  {*} key - key
+	 * @returns {*} Original key
+	 */
+	Map.prototype._getOriginKey = function(key) {
+	    var originKey = key;
+	    if (key === _KEY_FOR_UNDEFINED) {
+	        originKey = undefined; // eslint-disable-line no-undefined
+	    } else if (key === _KEY_FOR_NAN) {
+	        originKey = NaN;
+	    }
+	    return originKey;
+	};
+
+	/**
+	 * Returns the unique key of the specified key.
+	 * @private
+	 * @param  {*} key - key
+	 * @returns {*} Unique key
+	 */
+	Map.prototype._getUniqueKey = function(key) {
+	    var uniqueKey = key;
+	    if (type.isUndefined(key)) {
+	        uniqueKey = _KEY_FOR_UNDEFINED;
+	    } else if (this._isNaN(key)) {
+	        uniqueKey = _KEY_FOR_NAN;
+	    }
+	    return uniqueKey;
+	};
+
+	/**
+	 * Returns the value object of the specified key.
+	 * @private
+	 * @param  {*} key - The key of the value object to be returned
+	 * @param  {number} keyIndex - The index of the key
+	 * @returns {{keyIndex: number, origin: *}} Value object
+	 */
+	Map.prototype._getValueObject = function(key, keyIndex) { // eslint-disable-line consistent-return
+	    if (type.isString(key)) {
+	        return this._valuesForString[key];
+	    }
+
+	    if (type.isUndefined(keyIndex)) {
+	        keyIndex = this._getKeyIndex(key);
+	    }
+	    if (keyIndex >= 0) {
+	        return this._valuesForIndex[keyIndex];
+	    }
+	};
+
+	/**
+	 * Returns the original value of the specified key.
+	 * @private
+	 * @param  {*} key - The key of the value object to be returned
+	 * @param  {number} keyIndex - The index of the key
+	 * @returns {*} Original value
+	 */
+	Map.prototype._getOriginValue = function(key, keyIndex) {
+	    return this._getValueObject(key, keyIndex).origin;
+	};
+
+	/**
+	 * Returns key-value pair of the specified key.
+	 * @private
+	 * @param  {*} key - The key of the value object to be returned
+	 * @param  {number} keyIndex - The index of the key
+	 * @returns {Array} Key-value Pair
+	 */
+	Map.prototype._getKeyValuePair = function(key, keyIndex) {
+	    return [this._getOriginKey(key), this._getOriginValue(key, keyIndex)];
+	};
+
+	/**
+	 * Creates the wrapper object of original value that contains a key index
+	 * and returns it.
+	 * @private
+	 * @param  {type} origin - Original value
+	 * @param  {type} keyIndex - Index of the key
+	 * @returns {{keyIndex: number, origin: *}} Value object
+	 */
+	Map.prototype._createValueObject = function(origin, keyIndex) {
+	    return {
+	        keyIndex: keyIndex,
+	        origin: origin
+	    };
+	};
+
+	/**
+	 * Sets the value for the key in the Map object.
+	 * @param  {*} key - The key of the element to add to the Map object
+	 * @param  {*} value - The value of the element to add to the Map object
+	 * @returns {Map} The Map object
+	 */
+	Map.prototype.set = function(key, value) {
+	    var uniqueKey = this._getUniqueKey(key);
+	    var keyIndex = this._getKeyIndex(uniqueKey);
+	    var valueObject;
+
+	    if (keyIndex < 0) {
+	        keyIndex = this._keys.push(uniqueKey) - 1;
+	        this.size += 1;
+	    }
+	    valueObject = this._createValueObject(value, keyIndex);
+
+	    if (type.isString(key)) {
+	        this._valuesForString[key] = valueObject;
+	    } else {
+	        this._valuesForIndex[keyIndex] = valueObject;
+	    }
+	    return this;
+	};
+
+	/**
+	 * Returns the value associated to the key, or undefined if there is none.
+	 * @param  {*} key - The key of the element to return
+	 * @returns {*} Element associated with the specified key
+	 */
+	Map.prototype.get = function(key) {
+	    var uniqueKey = this._getUniqueKey(key);
+	    var value = this._getValueObject(uniqueKey);
+
+	    return value && value.origin;
+	};
+
+	/**
+	 * Returns a new Iterator object that contains the keys for each element
+	 * in the Map object in insertion order.
+	 * @returns {Iterator} A new Iterator object
+	 */
+	Map.prototype.keys = function() {
+	    return new MapIterator(this._keys, func.bind(this._getOriginKey, this));
+	};
+
+	/**
+	 * Returns a new Iterator object that contains the values for each element
+	 * in the Map object in insertion order.
+	 * @returns {Iterator} A new Iterator object
+	 */
+	Map.prototype.values = function() {
+	    return new MapIterator(this._keys, func.bind(this._getOriginValue, this));
+	};
+
+	/**
+	 * Returns a new Iterator object that contains the [key, value] pairs
+	 * for each element in the Map object in insertion order.
+	 * @returns {Iterator} A new Iterator object
+	 */
+	Map.prototype.entries = function() {
+	    return new MapIterator(this._keys, func.bind(this._getKeyValuePair, this));
+	};
+
+	/**
+	 * Returns a boolean asserting whether a value has been associated to the key
+	 * in the Map object or not.
+	 * @param  {*} key - The key of the element to test for presence
+	 * @returns {boolean} True if an element with the specified key exists;
+	 *          Otherwise false
+	 */
+	Map.prototype.has = function(key) {
+	    return !!this._getValueObject(key);
+	};
+
+	/**
+	 * Removes the specified element from a Map object.
+	 * @param {*} key - The key of the element to remove
+	 * @function delete
+	 * @memberof tui.util.Map.prototype
+	 */
+	// cannot use reserved keyword as a property name in IE8 and under.
+	Map.prototype['delete'] = function(key) {
+	    var keyIndex;
+
+	    if (type.isString(key)) {
+	        if (this._valuesForString[key]) {
+	            keyIndex = this._valuesForString[key].keyIndex;
+	            delete this._valuesForString[key];
+	        }
+	    } else {
+	        keyIndex = this._getKeyIndex(key);
+	        if (keyIndex >= 0) {
+	            delete this._valuesForIndex[keyIndex];
+	        }
+	    }
+
+	    if (keyIndex >= 0) {
+	        delete this._keys[keyIndex];
+	        this.size -= 1;
+	    }
+	};
+
+	/**
+	 * Executes a provided function once per each key/value pair in the Map object,
+	 * in insertion order.
+	 * @param  {function} callback - Function to execute for each element
+	 * @param  {thisArg} thisArg - Value to use as this when executing callback
+	 */
+	Map.prototype.forEach = function(callback, thisArg) {
+	    thisArg = thisArg || this;
+	    collection.forEachArray(this._keys, function(key) {
+	        if (!type.isUndefined(key)) {
+	            callback.call(thisArg, this._getValueObject(key).origin, key, this);
+	        }
+	    }, this);
+	};
+
+	/**
+	 * Removes all elements from a Map object.
+	 */
+	Map.prototype.clear = function() {
+	    Map.call(this);
+	};
+	/* eslint-enable no-extend-native */
+
+	// Use native Map object if exists.
+	// But only latest versions of Chrome and Firefox support full implementation.
+	(function() {
+	    if (window.Map && (
+	        (browser.firefox && browser.version >= 37) ||
+	            (browser.chrome && browser.version >= 42)
+	    )
+	    ) {
+	        Map = window.Map; // eslint-disable-line no-func-assign
+	    }
+	})();
+
+	module.exports = Map;
+
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/**
+	 * @fileoverview This module provides the HashMap constructor.
+	 * @author NHN Ent.
+	 *         FE Development Lab <dl_javascript@nhnent.com>
+	 * @dependency type, collection.js
+	 */
+
+	'use strict';
+
+	var collection = __webpack_require__(4);
+	var type = __webpack_require__(2);
+	/**
+	 * All the data in hashMap begin with _MAPDATAPREFIX;
+	 * @type {string}
+	 * @private
+	 */
+	var _MAPDATAPREFIX = 'å';
+
+	/**
+	 * HashMap can handle the key-value pairs.<br>
+	 * Caution:<br>
+	 *  HashMap instance has a length property but is not an instance of Array.
+	 * @param {Object} [obj] A initial data for creation.
+	 * @constructor
+	 * @memberof tui.util
+	 * @deprecated since version 1.3.0
+	 * @example
+	 *  var hm = new tui.util.HashMap({
+	 *      'mydata': {
+	 *           'hello': 'imfine'
+	 *       },
+	 *      'what': 'time'
+	 *  });
+	 */
+	function HashMap(obj) {
+	    /**
+	     * size
+	     * @type {number}
+	     */
+	    this.length = 0;
+
+	    if (obj) {
+	        this.setObject(obj);
+	    }
+	}
+
+	/**
+	 * Set a data from the given key with value or the given object.
+	 * @param {string|Object} key A string or object for key
+	 * @param {*} [value] A data
+	 * @example
+	 *  var hm = new HashMap();
+	 *
+	 *  hm.set('key', 'value');
+	 *  hm.set({
+	 *      'key1': 'data1',
+	 *      'key2': 'data2'
+	 *  });
+	 */
+	HashMap.prototype.set = function(key, value) {
+	    if (arguments.length === 2) {
+	        this.setKeyValue(key, value);
+	    } else {
+	        this.setObject(key);
+	    }
+	};
+
+	/**
+	 * Set a data from the given key with value.
+	 * @param {string} key A string for key
+	 * @param {*} value A data
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.setKeyValue('key', 'value');
+	 */
+	HashMap.prototype.setKeyValue = function(key, value) {
+	    if (!this.has(key)) {
+	        this.length += 1;
+	    }
+	    this[this.encodeKey(key)] = value;
+	};
+
+	/**
+	 * Set a data from the given object.
+	 * @param {Object} obj A object for data
+	 * @example
+	 *  var hm = new HashMap();
+	 *
+	 *  hm.setObject({
+	 *      'key1': 'data1',
+	 *      'key2': 'data2'
+	 *  });
+	 */
+	HashMap.prototype.setObject = function(obj) {
+	    var self = this;
+
+	    collection.forEachOwnProperties(obj, function(value, key) {
+	        self.setKeyValue(key, value);
+	    });
+	};
+
+	/**
+	 * Merge with the given another hashMap.
+	 * @param {HashMap} hashMap Another hashMap instance
+	 */
+	HashMap.prototype.merge = function(hashMap) {
+	    var self = this;
+
+	    hashMap.each(function(value, key) {
+	        self.setKeyValue(key, value);
+	    });
+	};
+
+	/**
+	 * Encode the given key for hashMap.
+	 * @param {string} key A string for key
+	 * @returns {string} A encoded key
+	 * @private
+	 */
+	HashMap.prototype.encodeKey = function(key) {
+	    return _MAPDATAPREFIX + key;
+	};
+
+	/**
+	 * Decode the given key in hashMap.
+	 * @param {string} key A string for key
+	 * @returns {string} A decoded key
+	 * @private
+	 */
+	HashMap.prototype.decodeKey = function(key) {
+	    var decodedKey = key.split(_MAPDATAPREFIX);
+	    return decodedKey[decodedKey.length - 1];
+	};
+
+	/**
+	 * Return the value from the given key.
+	 * @param {string} key A string for key
+	 * @returns {*} The value from a key
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *
+	 *  hm.get('key') // value
+	 */
+	HashMap.prototype.get = function(key) {
+	    return this[this.encodeKey(key)];
+	};
+
+	/**
+	 * Check the existence of a value from the key.
+	 * @param {string} key A string for key
+	 * @returns {boolean} Indicating whether a value exists or not.
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *
+	 *  hm.has('key') // true
+	 */
+	HashMap.prototype.has = function(key) {
+	    return this.hasOwnProperty(this.encodeKey(key));
+	};
+
+	/**
+	 * Remove a data(key-value pairs) from the given key or the given key-list.
+	 * @param {...string|string[]} key A string for key
+	 * @returns {string|string[]} A removed data
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *  hm.set('key2', 'value');
+	 *
+	 *  //ex1
+	 *  hm.remove('key');
+	 *
+	 *  //ex2
+	 *  hm.remove('key', 'key2');
+	 *
+	 *  //ex3
+	 *  hm.remove(['key', 'key2']);
+	 */
+	HashMap.prototype.remove = function(key) {
+	    if (arguments.length > 1) {
+	        key = collection.toArray(arguments);
+	    }
+
+	    return type.isArray(key) ? this.removeByKeyArray(key) : this.removeByKey(key);
+	};
+
+	/**
+	 * Remove data(key-value pair) from the given key.
+	 * @param {string} key A string for key
+	 * @returns {*|null} A removed data
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *
+	 *  hm.removeByKey('key')
+	 */
+	HashMap.prototype.removeByKey = function(key) {
+	    var data = this.has(key) ? this.get(key) : null;
+
+	    if (data !== null) {
+	        delete this[this.encodeKey(key)];
+	        this.length -= 1;
+	    }
+
+	    return data;
+	};
+
+	/**
+	 * Remove a data(key-value pairs) from the given key-list.
+	 * @param {string[]} keyArray An array of keys
+	 * @returns {string[]} A removed data
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *  hm.set('key2', 'value');
+	 *
+	 *  hm.removeByKeyArray(['key', 'key2']);
+	 */
+	HashMap.prototype.removeByKeyArray = function(keyArray) {
+	    var data = [];
+	    var self = this;
+
+	    collection.forEach(keyArray, function(key) {
+	        data.push(self.removeByKey(key));
+	    });
+
+	    return data;
+	};
+
+	/**
+	 * Remove all the data
+	 */
+	HashMap.prototype.removeAll = function() {
+	    var self = this;
+
+	    this.each(function(value, key) {
+	        self.remove(key);
+	    });
+	};
+
+	/**
+	 * Execute the provided callback once for each all the data.
+	 * @param {Function} iteratee Callback function
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *  hm.set('key2', 'value');
+	 *
+	 *  hm.each(function(value, key) {
+	 *      //do something...
+	 *  });
+	 */
+	HashMap.prototype.each = function(iteratee) {
+	    var self = this;
+	    var flag;
+
+	    collection.forEachOwnProperties(this, function(value, key) { // eslint-disable-line consistent-return
+	        if (key.charAt(0) === _MAPDATAPREFIX) {
+	            flag = iteratee(value, self.decodeKey(key));
+	        }
+
+	        if (flag === false) {
+	            return flag;
+	        }
+	    });
+	};
+
+	/**
+	 * Return the key-list stored.
+	 * @returns {Array} A key-list
+	 * @example
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *  hm.set('key2', 'value');
+	 *
+	 *  hm.keys();  //['key', 'key2');
+	 */
+	HashMap.prototype.keys = function() {
+	    var keys = [];
+	    var self = this;
+
+	    this.each(function(value, key) {
+	        keys.push(self.decodeKey(key));
+	    });
+
+	    return keys;
+	};
+
+	/**
+	 * Work similarly to Array.prototype.map().<br>
+	 * It executes the provided callback that checks conditions once for each element of hashMap,<br>
+	 *  and returns a new array having elements satisfying the conditions
+	 * @param {Function} condition A function that checks conditions
+	 * @returns {Array} A new array having elements satisfying the conditions
+	 * @example
+	 *  //ex1
+	 *  var hm = new HashMap();
+	 *  hm.set('key', 'value');
+	 *  hm.set('key2', 'value');
+	 *
+	 *  hm.find(function(value, key) {
+	 *      return key === 'key2';
+	 *  }); // ['value']
+	 *
+	 *  //ex2
+	 *  var hm = new HashMap({
+	 *      'myobj1': {
+	 *           visible: true
+	 *       },
+	 *      'mybobj2': {
+	 *           visible: false
+	 *       }
+	 *  });
+	 *
+	 *  hm.find(function(obj, key) {
+	 *      return obj.visible === true;
+	 *  }); // [{visible: true}];
+	 */
+	HashMap.prototype.find = function(condition) {
+	    var founds = [];
+
+	    this.each(function(value, key) {
+	        if (condition(value, key)) {
+	            founds.push(value);
+	        }
+	    });
+
+	    return founds;
+	};
+
+	/**
+	 * Return a new Array having all values.
+	 * @returns {Array} A new array having all values
+	 */
+	HashMap.prototype.toArray = function() {
+	    var result = [];
+
+	    this.each(function(v) {
+	        result.push(v);
+	    });
+
+	    return result;
+	};
+
+	module.exports = HashMap;
+
+
+/***/ })
+/******/ ])
+});
+;

File diff suppressed because it is too large
+ 6 - 0
public/assets/v1/common/lib/imageEditor/libs/tui-image-editor.min.js


+ 74 - 0
public/assets/v1/common/lib/nprogress/nprogress.css

@@ -0,0 +1,74 @@
+/* Make clicks pass-through */
+#nprogress {
+  pointer-events: none;
+}
+
+#nprogress .bar {
+  background: #29d;
+
+  position: fixed;
+  z-index: 1031;
+  top: 0;
+  left: 0;
+
+  width: 100%;
+  height: 2px;
+}
+
+/* Fancy blur effect */
+#nprogress .peg {
+  display: block;
+  position: absolute;
+  right: 0px;
+  width: 100px;
+  height: 100%;
+  box-shadow: 0 0 10px #29d, 0 0 5px #29d;
+  opacity: 1.0;
+
+  -webkit-transform: rotate(3deg) translate(0px, -4px);
+      -ms-transform: rotate(3deg) translate(0px, -4px);
+          transform: rotate(3deg) translate(0px, -4px);
+}
+
+/* Remove these to get rid of the spinner */
+#nprogress .spinner {
+  display: block;
+  position: fixed;
+  z-index: 1031;
+  top: 15px;
+  right: 15px;
+}
+
+#nprogress .spinner-icon {
+  width: 18px;
+  height: 18px;
+  box-sizing: border-box;
+
+  border: solid 2px transparent;
+  border-top-color: #29d;
+  border-left-color: #29d;
+  border-radius: 50%;
+
+  -webkit-animation: nprogress-spinner 400ms linear infinite;
+          animation: nprogress-spinner 400ms linear infinite;
+}
+
+.nprogress-custom-parent {
+  overflow: hidden;
+  position: relative;
+}
+
+.nprogress-custom-parent #nprogress .spinner,
+.nprogress-custom-parent #nprogress .bar {
+  position: absolute;
+}
+
+@-webkit-keyframes nprogress-spinner {
+  0%   { -webkit-transform: rotate(0deg); }
+  100% { -webkit-transform: rotate(360deg); }
+}
+@keyframes nprogress-spinner {
+  0%   { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+

+ 499 - 0
public/assets/v1/common/lib/nprogress/nprogress.js

@@ -0,0 +1,499 @@
+/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
+ * @license MIT */
+
+;(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(factory);
+  } else if (typeof exports === 'object') {
+    module.exports = factory();
+  } else {
+    root.NProgress = factory();
+  }
+
+})(this, function() {
+  var NProgress = {};
+
+  NProgress.version = '0.2.0';
+
+  var Settings = NProgress.settings = {
+    minimum: 0.08,
+    easing: 'linear',
+    positionUsing: '',
+    speed: 200,
+    trickle: true,
+    trickleSpeed: 200,
+    showSpinner: true,
+    barSelector: '[role="bar"]',
+    spinnerSelector: '[role="spinner"]',
+    parent: 'body',
+    template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
+  };
+
+  /**
+   * Updates configuration.
+   *
+   *     NProgress.configure({
+   *       minimum: 0.1
+   *     });
+   */
+  NProgress.configure = function(options) {
+    var key, value;
+    for (key in options) {
+      value = options[key];
+      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
+    }
+
+    return this;
+  };
+
+  /**
+   * Last number.
+   */
+
+  NProgress.status = null;
+
+  /**
+   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
+   *
+   *     NProgress.set(0.4);
+   *     NProgress.set(1.0);
+   */
+
+  NProgress.set = function(n) {
+    var started = NProgress.isStarted();
+
+    n = clamp(n, Settings.minimum, 1);
+    NProgress.status = (n === 1 ? null : n);
+
+    var progress = NProgress.render(!started),
+        bar      = progress.querySelector(Settings.barSelector),
+        speed    = Settings.speed,
+        ease     = Settings.easing;
+
+    progress.offsetWidth; /* Repaint */
+
+    queue(function(next) {
+      // Set positionUsing if it hasn't already been set
+      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();
+
+      // Add transition
+      css(bar, barPositionCSS(n, speed, ease));
+
+      if (n === 1) {
+        // Fade out
+        css(progress, {
+          transition: 'none',
+          opacity: 1
+        });
+        progress.offsetWidth; /* Repaint */
+
+        setTimeout(function() {
+          css(progress, {
+            transition: 'all ' + speed + 'ms linear',
+            opacity: 0
+          });
+          setTimeout(function() {
+            NProgress.remove();
+            next();
+          }, speed);
+        }, speed);
+      } else {
+        setTimeout(next, speed);
+      }
+    });
+
+    return this;
+  };
+
+  NProgress.isStarted = function() {
+    return typeof NProgress.status === 'number';
+  };
+
+  /**
+   * Shows the progress bar.
+   * This is the same as setting the status to 0%, except that it doesn't go backwards.
+   *
+   *     NProgress.start();
+   *
+   */
+  NProgress.start = function() {
+    if (!NProgress.status) NProgress.set(0);
+
+    var work = function() {
+      setTimeout(function() {
+        if (!NProgress.status) return;
+        NProgress.trickle();
+        work();
+      }, Settings.trickleSpeed);
+    };
+
+    if (Settings.trickle) work();
+
+    return this;
+  };
+
+  /**
+   * Hides the progress bar.
+   * This is the *sort of* the same as setting the status to 100%, with the
+   * difference being `done()` makes some placebo effect of some realistic motion.
+   *
+   *     NProgress.done();
+   *
+   * If `true` is passed, it will show the progress bar even if its hidden.
+   *
+   *     NProgress.done(true);
+   */
+
+  NProgress.done = function(force) {
+    if (!force && !NProgress.status) return this;
+
+    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
+  };
+
+  /**
+   * Increments by a random amount.
+   */
+
+  NProgress.inc = function(amount) {
+    var n = NProgress.status;
+
+    if (!n) {
+      return NProgress.start();
+    } else if(n > 1) {
+      return;
+    } else {
+      if (typeof amount !== 'number') {
+        if (n >= 0 && n < 0.2) { amount = 0.1; }
+        else if (n >= 0.2 && n < 0.5) { amount = 0.04; }
+        else if (n >= 0.5 && n < 0.8) { amount = 0.02; }
+        else if (n >= 0.8 && n < 0.99) { amount = 0.005; }
+        else { amount = 0; }
+      }
+
+      n = clamp(n + amount, 0, 0.994);
+      return NProgress.set(n);
+    }
+  };
+
+  NProgress.trickle = function() {
+    return NProgress.inc();
+  };
+
+  /**
+   * Waits for all supplied jQuery promises and
+   * increases the progress as the promises resolve.
+   *
+   * @param $promise jQUery Promise
+   */
+  (function() {
+    var initial = 0, current = 0;
+
+    NProgress.promise = function($promise) {
+      if (!$promise || $promise.state() === "resolved") {
+        return this;
+      }
+
+      if (current === 0) {
+        NProgress.start();
+      }
+
+      initial++;
+      current++;
+
+      $promise.always(function() {
+        current--;
+        if (current === 0) {
+            initial = 0;
+            NProgress.done();
+        } else {
+            NProgress.set((initial - current) / initial);
+        }
+      });
+
+      return this;
+    };
+
+  })();
+
+  /**
+   * (Internal) renders the progress bar markup based on the `template`
+   * setting.
+   */
+
+  NProgress.render = function(fromStart) {
+    if (NProgress.isRendered()) return document.getElementById('nprogress');
+
+    addClass(document.documentElement, 'nprogress-busy');
+
+    var progress = document.createElement('div');
+    progress.id = 'nprogress';
+    progress.innerHTML = Settings.template;
+
+
+
+    var bar = progress.querySelector(Settings.barSelector),
+        perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
+        parent = isDOM(Settings.parent)
+          ? Settings.parent
+          : document.querySelector(Settings.parent),
+        spinner
+
+    css(bar, {
+      transition: 'all 0 linear',
+      transform: 'translate3d(' + perc + '%,0,0)'
+    });
+
+    if (!Settings.showSpinner) {
+      spinner = progress.querySelector(Settings.spinnerSelector);
+      spinner && removeElement(spinner);
+    }
+
+    if (parent != document.body) {
+      addClass(parent, 'nprogress-custom-parent');
+    }
+
+    parent.appendChild(progress);
+    return progress;
+  };
+
+  /**
+   * Removes the element. Opposite of render().
+   */
+
+  NProgress.remove = function() {
+    removeClass(document.documentElement, 'nprogress-busy');
+    var parent = isDOM(Settings.parent)
+      ? Settings.parent
+      : document.querySelector(Settings.parent)
+    removeClass(parent, 'nprogress-custom-parent')
+    var progress = document.getElementById('nprogress');
+    progress && removeElement(progress);
+  };
+
+  /**
+   * Checks if the progress bar is rendered.
+   */
+
+  NProgress.isRendered = function() {
+    return !!document.getElementById('nprogress');
+  };
+
+  /**
+   * Determine which positioning CSS rule to use.
+   */
+
+  NProgress.getPositioningCSS = function() {
+    // Sniff on document.body.style
+    var bodyStyle = document.body.style;
+
+    // Sniff prefixes
+    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
+                       ('MozTransform' in bodyStyle) ? 'Moz' :
+                       ('msTransform' in bodyStyle) ? 'ms' :
+                       ('OTransform' in bodyStyle) ? 'O' : '';
+
+    if (vendorPrefix + 'Perspective' in bodyStyle) {
+      // Modern browsers with 3D support, e.g. Webkit, IE10
+      return 'translate3d';
+    } else if (vendorPrefix + 'Transform' in bodyStyle) {
+      // Browsers without 3D support, e.g. IE9
+      return 'translate';
+    } else {
+      // Browsers without translate() support, e.g. IE7-8
+      return 'margin';
+    }
+  };
+
+  /**
+   * Helpers
+   */
+
+  function isDOM (obj) {
+    if (typeof HTMLElement === 'object') {
+      return obj instanceof HTMLElement
+    }
+    return (
+      obj &&
+      typeof obj === 'object' &&
+      obj.nodeType === 1 &&
+      typeof obj.nodeName === 'string'
+    )
+  }
+
+  function clamp(n, min, max) {
+    if (n < min) return min;
+    if (n > max) return max;
+    return n;
+  }
+
+  /**
+   * (Internal) converts a percentage (`0..1`) to a bar translateX
+   * percentage (`-100%..0%`).
+   */
+
+  function toBarPerc(n) {
+    return (-1 + n) * 100;
+  }
+
+
+  /**
+   * (Internal) returns the correct CSS for changing the bar's
+   * position given an n percentage, and speed and ease from Settings
+   */
+
+  function barPositionCSS(n, speed, ease) {
+    var barCSS;
+
+    if (Settings.positionUsing === 'translate3d') {
+      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
+    } else if (Settings.positionUsing === 'translate') {
+      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
+    } else {
+      barCSS = { 'margin-left': toBarPerc(n)+'%' };
+    }
+
+    barCSS.transition = 'all '+speed+'ms '+ease;
+
+    return barCSS;
+  }
+
+  /**
+   * (Internal) Queues a function to be executed.
+   */
+
+  var queue = (function() {
+    var pending = [];
+
+    function next() {
+      var fn = pending.shift();
+      if (fn) {
+        fn(next);
+      }
+    }
+
+    return function(fn) {
+      pending.push(fn);
+      if (pending.length == 1) next();
+    };
+  })();
+
+  /**
+   * (Internal) Applies css properties to an element, similar to the jQuery
+   * css method.
+   *
+   * While this helper does assist with vendor prefixed property names, it
+   * does not perform any manipulation of values prior to setting styles.
+   */
+
+  var css = (function() {
+    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
+        cssProps    = {};
+
+    function camelCase(string) {
+      return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
+        return letter.toUpperCase();
+      });
+    }
+
+    function getVendorProp(name) {
+      var style = document.body.style;
+      if (name in style) return name;
+
+      var i = cssPrefixes.length,
+          capName = name.charAt(0).toUpperCase() + name.slice(1),
+          vendorName;
+      while (i--) {
+        vendorName = cssPrefixes[i] + capName;
+        if (vendorName in style) return vendorName;
+      }
+
+      return name;
+    }
+
+    function getStyleProp(name) {
+      name = camelCase(name);
+      return cssProps[name] || (cssProps[name] = getVendorProp(name));
+    }
+
+    function applyCss(element, prop, value) {
+      prop = getStyleProp(prop);
+      element.style[prop] = value;
+    }
+
+    return function(element, properties) {
+      var args = arguments,
+          prop,
+          value;
+
+      if (args.length == 2) {
+        for (prop in properties) {
+          value = properties[prop];
+          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
+        }
+      } else {
+        applyCss(element, args[1], args[2]);
+      }
+    }
+  })();
+
+  /**
+   * (Internal) Determines if an element or space separated list of class names contains a class name.
+   */
+
+  function hasClass(element, name) {
+    var list = typeof element == 'string' ? element : classList(element);
+    return list.indexOf(' ' + name + ' ') >= 0;
+  }
+
+  /**
+   * (Internal) Adds a class to an element.
+   */
+
+  function addClass(element, name) {
+    var oldList = classList(element),
+        newList = oldList + name;
+
+    if (hasClass(oldList, name)) return;
+
+    // Trim the opening space.
+    element.className = newList.substring(1);
+  }
+
+  /**
+   * (Internal) Removes a class from an element.
+   */
+
+  function removeClass(element, name) {
+    var oldList = classList(element),
+        newList;
+
+    if (!hasClass(element, name)) return;
+
+    // Replace the class name.
+    newList = oldList.replace(' ' + name + ' ', ' ');
+
+    // Trim the opening and closing spaces.
+    element.className = newList.substring(1, newList.length - 1);
+  }
+
+  /**
+   * (Internal) Gets a space separated list of the class names on the element.
+   * The list is wrapped with a single space on each end to facilitate finding
+   * matches within the list.
+   */
+
+  function classList(element) {
+    return (' ' + (element && element.className || '') + ' ').replace(/\s+/gi, ' ');
+  }
+
+  /**
+   * (Internal) Removes an element from the DOM.
+   */
+
+  function removeElement(element) {
+    element && element.parentNode && element.parentNode.removeChild(element);
+  }
+
+  return NProgress;
+});

File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/lib/tinymce/icons/default/icons.min.js


+ 92 - 0
public/assets/v1/common/lib/tinymce/jquery.tinymce.min.js

@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ */
+/**
+ * Jquery integration plugin.
+ *
+ * @class tinymce.core.JqueryIntegration
+ * @private
+ */
+!function(){var f,c,u,s=[],p="undefined"!=typeof global?global:window,d=p.jQuery,v=function(){
+// Reference to tinymce needs to be lazily evaluated since tinymce
+// might be loaded through the compressor or other means
+return p.tinymce};d.fn.tinymce=function(o){var e,t,i,l=this,r="";
+// No match then just ignore the call
+if(!l.length)return l;
+// Get editor instance
+if(!o)return v()?v().get(l[0].id):null;l.css("visibility","hidden");// Hide textarea to avoid flicker
+var n,a=function(){var a=[],c=0;
+// Apply patches to the jQuery object, only once
+u||(m(),u=!0),
+// Create an editor instance for each matched node
+l.each(function(e,t){var n,i=t.id,r=o.oninit;
+// Generate unique id for target element if needed
+i||(t.id=i=v().DOM.uniqueId()),
+// Only init the editor once
+v().get(i)||(
+// Create editor instance and render it
+n=v().createEditor(i,o),a.push(n),n.on("init",function(){var e,t=r;l.css("visibility",""),
+// Run this if the oninit setting is defined
+// this logic will fire the oninit callback ones each
+// matched editor instance is initialized
+r&&++c==a.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:v().resolve(t.replace(/\.\w+$/,"")),t=v().resolve(t)),
+// Call the oninit function with the object
+t.apply(e||v(),a))}))}),
+// Render the editor instances in a separate loop since we
+// need to have the full editors array used in the onInit calls
+d.each(a,function(e,t){t.render()})};
+// Load TinyMCE on demand, if we need to
+return p.tinymce||c||!(e=o.script_url)?
+// Delay the init call until tinymce is loaded
+1===c?s.push(a):a():(c=1,t=e.substring(0,e.lastIndexOf("/")),
+// Check if it's a dev/src version they want to load then
+// make sure that all plugins, themes etc are loaded in source mode as well
+-1!=e.indexOf(".min")&&(r=".min"),
+// Setup tinyMCEPreInit object this will later be used by the TinyMCE
+// core script to locate other resources like CSS files, dialogs etc
+// You can also predefined a tinyMCEPreInit object and then it will use that instead
+p.tinymce=p.tinyMCEPreInit||{base:t,suffix:r},
+// url contains gzip then we assume it's a compressor
+-1!=e.indexOf("gzip")&&(i=o.language||"en",e=e+(/\?/.test(e)?"&":"?")+"js=true&core=true&suffix="+escape(r)+"&themes="+escape(o.theme||"modern")+"&plugins="+escape(o.plugins||"")+"&languages="+(i||""),
+// Check if compressor script is already loaded otherwise setup a basic one
+p.tinyMCE_GZ||(p.tinyMCE_GZ={start:function(){var n=function(e){v().ScriptLoader.markDone(v().baseURI.toAbsolute(e))};
+// Add core languages
+n("langs/"+i+".js"),
+// Add themes with languages
+n("themes/"+o.theme+"/theme"+r+".js"),n("themes/"+o.theme+"/langs/"+i+".js"),
+// Add plugins with languages
+d.each(o.plugins.split(","),function(e,t){t&&(n("plugins/"+t+"/plugin"+r+".js"),n("plugins/"+t+"/langs/"+i+".js"))})},end:function(){}})),(n=document.createElement("script")).type="text/javascript",n.onload=n.onreadystatechange=function(e){e=e||window.event,2===c||"load"!=e.type&&!/complete|loaded/.test(n.readyState)||(v().dom.Event.domLoaded=1,c=2,
+// Execute callback after mainscript has been loaded and before the initialization occurs
+o.script_loaded&&o.script_loaded(),a(),d.each(s,function(e,t){t()}))},n.src=e,document.body.appendChild(n)),l},
+// Add :tinymce pseudo selector this will select elements that has been converted into editor instances
+// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
+d.extend(d.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in p&&(t=v().get(e.id))&&t.editorManager===v())}});
+// This function patches internal jQuery functions so that if
+// you for example remove an div element containing an editor it's
+// automatically destroyed by the TinyMCE API
+var m=function(){
+// Removes any child editor instances by looking for editor wrapper elements
+var r=function(e){
+// If the function is remove
+"remove"===e&&this.each(function(e,t){var n=l(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=v().get(t.id.replace(/_parent$/,""));n&&n.remove()})},o=function(i){var e,t=this;
+// Handle set value
+/*jshint eqnull:true */if(null!=i)r.call(t),
+// Saves the contents before get/set value of textarea/div
+t.each(function(e,t){var n;(n=v().get(t.id))&&n.setContent(i)});else if(0<t.length&&(e=v().get(t[0].id)))return e.getContent()},l=function(e){var t=null;return e&&e.id&&p.tinymce&&(t=v().get(e.id)),t},u=function(e){return!!(e&&e.length&&p.tinymce&&e.is(":tinymce"))},s={};
+// Loads or saves contents from/to textarea if the value
+// argument is defined it will set the TinyMCE internal contents
+// Patch some setter/getter functions these will
+// now be able to set/get the contents of editor instances for
+// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
+d.each(["text","html","val"],function(e,t){var a=s[t]=d.fn[t],c="text"===t;d.fn[t]=function(e){var t=this;if(!u(t))return a.apply(t,arguments);if(e!==f)return o.call(t.filter(":tinymce"),e),a.apply(t.not(":tinymce"),arguments),t;// return original set for chaining
+var i="",r=arguments;return(c?t:t.eq(0)).each(function(e,t){var n=l(t);i+=n?c?n.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):n.getContent({save:!0}):a.apply(d(t),r)}),i}}),
+// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
+d.each(["append","prepend"],function(e,t){var n=s[t]=d.fn[t],r="prepend"===t;d.fn[t]=function(i){var e=this;return u(e)?i!==f?("string"==typeof i&&e.filter(":tinymce").each(function(e,t){var n=l(t);n&&n.setContent(r?i+n.getContent():n.getContent()+i)}),n.apply(e.not(":tinymce"),arguments),e):void 0:n.apply(e,arguments)}}),
+// Makes sure that the editor instance gets properly destroyed when the parent element is removed
+d.each(["remove","replaceWith","replaceAll","empty"],function(e,t){var n=s[t]=d.fn[t];d.fn[t]=function(){return r.call(this,t),n.apply(this,arguments)}}),s.attr=d.fn.attr,
+// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
+d.fn.attr=function(e,t){var n=this,i=arguments;if(!e||"value"!==e||!u(n))return s.attr.apply(n,i);if(t!==f)return o.call(n.filter(":tinymce"),t),s.attr.apply(n.not(":tinymce"),i),n;// return original set for chaining
+var r=n[0],a=l(r);return a?a.getContent({save:!0}):s.attr.apply(d(r),i)}}}();

+ 3 - 0
public/assets/v1/common/lib/tinymce/langs/readme.md

@@ -0,0 +1,3 @@
+This is where language files should be placed.
+
+Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/

+ 410 - 0
public/assets/v1/common/lib/tinymce/langs/zh_CN.js

@@ -0,0 +1,410 @@
+tinymce.addI18n('zh_CN',{
+"Redo": "恢复",
+"Undo": "撤销",
+"Cut": "剪切",
+"Copy": "复制",
+"Paste": "粘贴",
+"Select all": "全选",
+"New document": "新建文档",
+"Ok": "确定",
+"Cancel": "取消",
+"Visual aids": "网格线",
+"Bold": "粗体",
+"Italic": "斜体",
+"Underline": "下划线",
+"Strikethrough": "删除线",
+"Superscript": "上标",
+"Subscript": "下标",
+"Clear formatting": "清除格式",
+"Align left": "左对齐",
+"Align center": "居中",
+"Align right": "右对齐",
+"Justify": "两端对齐",
+"Bullet list": "符号列表",
+"Numbered list": "数字列表",
+"Decrease indent": "减少缩进",
+"Increase indent": "增加缩进",
+"Close": "关闭",
+"Formats": "格式",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "当前浏览器不支持访问剪贴板,请使用快捷键Ctrl+X/C/V复制粘贴",
+"Headers": "标题",
+"Header 1": "标题1",
+"Header 2": "标题2",
+"Header 3": "标题3",
+"Header 4": "标题4",
+"Header 5": "标题5",
+"Header 6": "标题6",
+"Headings": "标题",
+"Heading 1": "标题1",
+"Heading 2": "标题2",
+"Heading 3": "标题3",
+"Heading 4": "标题4",
+"Heading 5": "标题5",
+"Heading 6": "标题6",
+"Preformatted": "预格式化",
+"Div": "Div区块",
+"Pre": "预格式文本",
+"Code": "代码",
+"Paragraph": "段落",
+"Blockquote": "引用",
+"Inline": "文本",
+"Blocks": "区块",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "当前为纯文本粘贴模式,再次点击可以回到普通粘贴模式。",
+"Fonts": "字体",
+"Font Sizes": "字号",
+"Class": "Class",
+"Browse for an image": "浏览图像",
+"OR": "或",
+"Drop an image here": "拖放一张图片文件至此",
+"Upload": "上传",
+"Block": "块",
+"Align": "对齐",
+"Default": "默认",
+"Circle": "空心圆",
+"Disc": "实心圆",
+"Square": "方块",
+"Lower Alpha": "小写英文字母",
+"Lower Greek": "小写希腊字母",
+"Lower Roman": "小写罗马字母",
+"Upper Alpha": "大写英文字母",
+"Upper Roman": "大写罗马字母",
+"Anchor...": "锚点...",
+"Name": "名称",
+"Id": "id",
+"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "id应该以字母开头,后跟字母、数字、横线、点、冒号或下划线。",
+"You have unsaved changes are you sure you want to navigate away?": "你对文档的修改尚未保存,确定离开吗?",
+"Restore last draft": "恢复上次的草稿",
+"Special characters...": "特殊字符...",
+"Source code": "HTML源码",
+"Insert\/Edit code sample": "插入/编辑代码示例",
+"Language": "语言",
+"Code sample...": "代码示例...",
+"Color Picker": "选取颜色",
+"R": "R",
+"G": "G",
+"B": "B",
+"Left to right": "从左到右",
+"Right to left": "从右到左",
+"Emoticons...": "表情符号...",
+"Metadata and Document Properties": "元数据和文档属性",
+"Title": "标题",
+"Keywords": "关键词",
+"Description": "描述",
+"Robots": "机器人",
+"Author": "作者",
+"Encoding": "编码",
+"Fullscreen": "全屏",
+"Action": "操作",
+"Shortcut": "快捷键",
+"Help": "帮助",
+"Address": "地址",
+"Focus to menubar": "移动焦点到菜单栏",
+"Focus to toolbar": "移动焦点到工具栏",
+"Focus to element path": "移动焦点到元素路径",
+"Focus to contextual toolbar": "移动焦点到上下文菜单",
+"Insert link (if link plugin activated)": "插入链接 (如果链接插件已激活)",
+"Save (if save plugin activated)": "保存(如果保存插件已激活)",
+"Find (if searchreplace plugin activated)": "查找(如果查找替换插件已激活)",
+"Plugins installed ({0}):": "已安装插件 ({0}):",
+"Premium plugins:": "优秀插件:",
+"Learn more...": "了解更多...",
+"You are using {0}": "你正在使用 {0}",
+"Plugins": "插件",
+"Handy Shortcuts": "快捷键",
+"Horizontal line": "水平分割线",
+"Insert\/edit image": "插入/编辑图片",
+"Image description": "图片描述",
+"Source": "地址",
+"Dimensions": "大小",
+"Constrain proportions": "保持宽高比",
+"General": "常规",
+"Advanced": "高级",
+"Style": "样式",
+"Vertical space": "垂直边距",
+"Horizontal space": "水平边距",
+"Border": "边框",
+"Insert image": "插入图片",
+"Image...": "图片...",
+"Image list": "图片列表",
+"Rotate counterclockwise": "逆时针旋转",
+"Rotate clockwise": "顺时针旋转",
+"Flip vertically": "垂直翻转",
+"Flip horizontally": "水平翻转",
+"Edit image": "编辑图片",
+"Image options": "图片选项",
+"Zoom in": "放大",
+"Zoom out": "缩小",
+"Crop": "裁剪",
+"Resize": "调整大小",
+"Orientation": "方向",
+"Brightness": "亮度",
+"Sharpen": "锐化",
+"Contrast": "对比度",
+"Color levels": "色阶",
+"Gamma": "伽马值",
+"Invert": "反转",
+"Apply": "应用",
+"Back": "后退",
+"Insert date\/time": "插入日期/时间",
+"Date\/time": "日期/时间",
+"Insert\/Edit Link": "插入/编辑链接",
+"Insert\/edit link": "插入/编辑链接",
+"Text to display": "显示文字",
+"Url": "地址",
+"Open link in...": "链接打开方式...",
+"Current window": "当前窗口打开",
+"None": "在当前窗口/框架打开",
+"New window": "在新窗口打开",
+"Remove link": "删除链接",
+"Anchors": "锚点",
+"Link...": "链接...",
+"Paste or type a link": "粘贴或输入链接",
+"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "你所填写的URL地址为邮件地址,需要加上mailto:前缀吗?",
+"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "你所填写的URL地址属于外部链接,需要加上http://:前缀吗?",
+"Link list": "链接列表",
+"Insert video": "插入视频",
+"Insert\/edit video": "插入/编辑视频",
+"Insert\/edit media": "插入/编辑媒体",
+"Alternative source": "替代资源",
+"Alternative image URL": "资源备用地址",
+"Media poster (Image URL)": "封面(图片地址)",
+"Paste your embed code below:": "将内嵌代码粘贴在下面:",
+"Embed": "内嵌",
+"Media...": "多媒体...",
+"Nonbreaking space": "不间断空格",
+"Page break": "分页符",
+"Paste as text": "粘贴为文本",
+"Preview": "预览",
+"Print...": "打印...",
+"Save": "保存",
+"Find": "查找",
+"Replace with": "替换为",
+"Replace": "替换",
+"Replace all": "替换全部",
+"Previous": "上一个",
+"Next": "下一个",
+"Find and replace...": "查找并替换...",
+"Could not find the specified string.": "未找到搜索内容。",
+"Match case": "区分大小写",
+"Find whole words only": "全单词匹配",
+"Spell check": "拼写检查",
+"Ignore": "忽略",
+"Ignore all": "忽略全部",
+"Finish": "完成",
+"Add to Dictionary": "添加到字典",
+"Insert table": "插入表格",
+"Table properties": "表格属性",
+"Delete table": "删除表格",
+"Cell": "单元格",
+"Row": "行",
+"Column": "列",
+"Cell properties": "单元格属性",
+"Merge cells": "合并单元格",
+"Split cell": "拆分单元格",
+"Insert row before": "在上方插入",
+"Insert row after": "在下方插入",
+"Delete row": "删除行",
+"Row properties": "行属性",
+"Cut row": "剪切行",
+"Copy row": "复制行",
+"Paste row before": "粘贴到上方",
+"Paste row after": "粘贴到下方",
+"Insert column before": "在左侧插入",
+"Insert column after": "在右侧插入",
+"Delete column": "删除列",
+"Cols": "列",
+"Rows": "行",
+"Width": "宽",
+"Height": "高",
+"Cell spacing": "单元格外间距",
+"Cell padding": "单元格内边距",
+"Show caption": "显示标题",
+"Left": "左对齐",
+"Center": "居中",
+"Right": "右对齐",
+"Cell type": "单元格类型",
+"Scope": "范围",
+"Alignment": "对齐方式",
+"H Align": "水平对齐",
+"V Align": "垂直对齐",
+"Top": "顶部对齐",
+"Middle": "垂直居中",
+"Bottom": "底部对齐",
+"Header cell": "表头单元格",
+"Row group": "行组",
+"Column group": "列组",
+"Row type": "行类型",
+"Header": "表头",
+"Body": "表体",
+"Footer": "表尾",
+"Border color": "边框颜色",
+"Insert template...": "插入模板...",
+"Templates": "模板",
+"Template": "模板",
+"Text color": "文字颜色",
+"Background color": "背景色",
+"Custom...": "自定义...",
+"Custom color": "自定义颜色",
+"No color": "无",
+"Remove color": "删除颜色",
+"Table of Contents": "目录",
+"Show blocks": "显示区块边框",
+"Show invisible characters": "显示不可见字符",
+"Word count": "字数统计",
+"Words: {0}": "字数:{0}",
+"{0} words": "{0} 个字",
+"File": "文件",
+"Edit": "编辑",
+"Insert": "插入",
+"View": "查看",
+"Format": "格式",
+"Table": "表格",
+"Tools": "工具",
+"Powered by {0}": "Powered by {0}",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "在编辑区按ALT+F9打开菜单,按ALT+F10打开工具栏,按ALT+0查看帮助",
+"Image title": "图片标题",
+"Border width": "边框宽度",
+"Border style": "边框样式",
+"Error": "错误",
+"Warn": "警告",
+"Valid": "有效",
+"To open the popup, press Shift+Enter": "此快捷为软回车(插入<br>)",
+"Rich Text Area. Press ALT-0 for help.": "编辑区. 按Alt+0键打开帮助",
+"System Font": "默认字体",
+"Failed to upload image: {0}": "图片上传失败: {0}",
+"Failed to load plugin: {0} from url {1}": "插件加载失败: {0} - {1}",
+"Failed to load plugin url: {0}": "插件加载失败: {0}",
+"Failed to initialize plugin: {0}": "插件初始化失败: {0}",
+"example": "示例",
+"Search": "查找",
+"All": "全部",
+"Currency": "货币",
+"Text": "文本",
+"Quotations": "引用",
+"Mathematical": "数学运算符",
+"Extended Latin": "拉丁语扩充",
+"Symbols": "符号",
+"Arrows": "箭头",
+"User Defined": "自定义",
+"dollar sign": "美元",
+"currency sign": "货币",
+"euro-currency sign": "欧元",
+"colon sign": "冒号",
+"cruzeiro sign": "克鲁赛罗币",
+"french franc sign": "法郎",
+"lira sign": "里拉",
+"mill sign": "密尔",
+"naira sign": "奈拉",
+"peseta sign": "比塞塔",
+"rupee sign": "卢比",
+"won sign": "韩元",
+"new sheqel sign": "新谢克尔",
+"dong sign": "越南盾",
+"kip sign": "老挝基普",
+"tugrik sign": "图格里克",
+"drachma sign": "德拉克马",
+"german penny symbol": "德国便士",
+"peso sign": "比索",
+"guarani sign": "瓜拉尼",
+"austral sign": "澳元",
+"hryvnia sign": "格里夫尼亚",
+"cedi sign": "塞地",
+"livre tournois sign": "里弗弗尔",
+"spesmilo sign": "一千spesoj的货币符号,该货币未使用",
+"tenge sign": "坚戈",
+"indian rupee sign": "印度卢比",
+"turkish lira sign": "土耳其里拉",
+"nordic mark sign": "北欧马克",
+"manat sign": "马纳特",
+"ruble sign": "卢布",
+"yen character": "日元",
+"yuan character": "人民币元",
+"yuan character, in hong kong and taiwan": "元的繁体字",
+"yen\/yuan character variant one": "元(大写)",
+"Loading emoticons...": "正在加载表情文字...",
+"Could not load emoticons": "不能加载表情文字",
+"People": "人类",
+"Animals and Nature": "动物和自然",
+"Food and Drink": "食物和饮品",
+"Activity": "活动",
+"Travel and Places": "旅游和地点",
+"Objects": "物件",
+"Flags": "旗帜",
+"Characters": "字数",
+"Characters (no spaces)": "字数(不含空格)",
+"Error: Form submit field collision.": "错误: 表单提交字段冲突.",
+"Error: No form element found.": "错误: 未找到可用的form.",
+"Update": "更新",
+"Color swatch": "颜色样本",
+"Turquoise": "青绿",
+"Green": "绿色",
+"Blue": "蓝色",
+"Purple": "紫色",
+"Navy Blue": "海军蓝",
+"Dark Turquoise": "深蓝绿色",
+"Dark Green": "暗绿",
+"Medium Blue": "中蓝",
+"Medium Purple": "中紫",
+"Midnight Blue": "深蓝",
+"Yellow": "黄色",
+"Orange": "橙色",
+"Red": "红色",
+"Light Gray": "浅灰",
+"Gray": "灰色",
+"Dark Yellow": "暗黄",
+"Dark Orange": "暗橙",
+"Dark Red": "暗红",
+"Medium Gray": "中灰",
+"Dark Gray": "深灰",
+"Black": "黑色",
+"White": "白色",
+"Switch to or from fullscreen mode": "切换全屏模式",
+"Open help dialog": "打开帮助对话框",
+"history": "历史",
+"styles": "样式",
+"formatting": "格式化",
+"alignment": "对齐",
+"indentation": "缩进",
+"permanent pen": "记号笔",
+"comments": "注释",
+"Anchor": "锚点",
+"Special character": "特殊字符",
+"Code sample": "代码示例",
+"Color": "颜色",
+"Emoticons": "表情",
+"Document properties": "文档属性",
+"Image": "图片",
+"Insert link": "插入链接",
+"Target": "目标",
+"Link": "链接",
+"Poster": "封面",
+"Media": "音视频",
+"Print": "打印",
+"Prev": "上一个",
+"Find and replace": "查找并替换",
+"Whole words": "全字匹配",
+"Spellcheck": "拼写检查",
+"Caption": "标题",
+"Insert template": "插入模板",
+//以下为补充汉化内容 by 莫若卿
+"Code view": "代码区域",
+"Select...": "选择...",
+"Format Painter": "格式刷",
+"No templates defined.": "无内置模板",
+"Special character...": "特殊字符...",
+"Open link": "打开链接",
+"None": "无",
+"Count": "统计",
+"Document": "整个文档",
+"Selection": "选取部分",
+"Words": "字词数",
+"{0} characters": "{0} 个字符",
+"Alternative source URL": "替代资源地址",
+"Alternative description": "替代说明文字",
+"Accessibility": "可访问性",
+"Image is decorative": "仅用于装饰",
+//帮助窗口内的文字
+"Version": "版本",
+"Keyboard Navigation": "键盘导航",
+"Open popup menu for split buttons": "该组合键的作用是软回车(插入br)",
+});

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/advlist/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/anchor/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/autolink/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/autoresize/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),h=tinymce.util.Tools.resolve("tinymce.Env"),r=tinymce.util.Tools.resolve("tinymce.util.Delay"),y=function(e){return e.getParam("min_height",e.getElement().offsetHeight,"number")},a=function(e,t,n,i,o){r.setEditorTimeout(e,function(){b(e,t),n--?a(e,t,n,i,o):o&&o()},i)},p=function(e,t){var n=e.getBody();n&&(n.style.overflowY=t?"":"hidden",t||(n.scrollTop=0))},v=function(e,t,n,i){var o=parseInt(e.getStyle(t,n,i),10);return isNaN(o)?0:o},b=function(e,t){var n,i,o,r,s,a,g,u,l,c,m,f=e.dom,d=e.getDoc();d&&((n=e).plugins.fullscreen&&n.plugins.fullscreen.isFullscreen()?p(e,!0):(i=d.documentElement,o=e.getParam("autoresize_bottom_margin",50,"number"),r=y(e),s=v(f,i,"margin-top",!0),a=v(f,i,"margin-bottom",!0),(g=i.offsetHeight+s+a+o)<0&&(g=0),g+(u=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight)>y(e)&&(r=g+u),(l=e.getParam("max_height",0,"number"))&&l<r?(r=l,p(e,!0)):p(e,!1),r!==t.get()&&(c=r-t.get(),f.setStyle(e.getContainer(),"height",r+"px"),t.set(r),e.fire("ResizeEditor"),h.browser.isSafari()&&h.mac&&(m=e.getWin()).scrollTo(m.pageXOffset,m.pageYOffset),e.hasFocus()&&e.selection.scrollIntoView(e.selection.getNode()),h.webkit&&c<0&&b(e,t))))};e.add("autoresize",function(e){var t,n,i,o,r,s;e.settings.hasOwnProperty("resize")||(e.settings.resize=!1),e.inline||(s=0,r=t={get:function(){return s},set:function(e){s=e}},(o=e).addCommand("mceAutoResize",function(){b(o,r)}),i=t,(n=e).on("init",function(){var e=n.getParam("autoresize_overflow_padding",1,"number"),t=n.dom;t.setStyles(n.getDoc().documentElement,{height:"auto"}),t.setStyles(n.getBody(),{paddingLeft:e,paddingRight:e,"min-height":0})}),n.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",function(){b(n,i)}),n.getParam("autoresize_on_init",!0,"boolean")&&n.on("init",function(){a(n,i,20,100,function(){a(n,i,5,1e3)})}))})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/autosave/plugin.min.js


+ 55 - 0
public/assets/v1/common/lib/tinymce/plugins/ax_wordlimit/plugin.js

@@ -0,0 +1,55 @@
+tinymce.PluginManager.add('ax_wordlimit', function(editor) {
+    var pluginName='字数限制';
+    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
+    var ax_wordlimit_type = editor.getParam('ax_wordlimit_type', 'letter' );
+    var ax_wordlimit_num = editor.getParam('ax_wordlimit_num', false );
+    var ax_wordlimit_delay = editor.getParam('ax_wordlimit_delay', 500 );
+    var ax_wordlimit_callback = editor.getParam('ax_wordlimit_callback', function(){} );
+    var ax_wordlimit_event = editor.getParam('ax_wordlimit_event', 'SetContent Undo Redo Keyup' );
+    var onsign=1;
+    //统计方法1:计算总字符数
+    var sumLetter = function(){
+        var html = editor.getContent();
+        var re1 = new RegExp("<.+?>","g");
+        var txt = html.replace(re1,'');
+        txt = txt.replace(/\n/g,'');
+        txt = txt.replace(/&nbsp;/g,' ');
+        var num=txt.length;
+        return {txt:txt,num:num}
+    }
+    var onAct = function(){
+        if(onsign){
+            onsign=0;
+            //此处预留更多统计方法
+            switch(ax_wordlimit_type){
+                case 'letter':
+                default:
+                    var res = sumLetter();
+            }
+            if( res.num > ax_wordlimit_num ){
+                ax_wordlimit_callback(editor, res.txt, ax_wordlimit_num);
+            }
+            setTimeout(function(){onsign=1}, ax_wordlimit_delay);
+        }
+        
+    };
+    var setup = function(){
+        if( ax_wordlimit_num>0 ){
+            global$2.setEditorTimeout(editor, function(){
+                var doth = editor.on(ax_wordlimit_event, onAct);
+            }, 300);
+        }
+    };
+
+    setup();
+
+    return {
+        getMetadata: function () {
+            return  {
+                name: pluginName,
+                url: "http://tinymce.ax-z.cn/more-plugins/ax_wordlimit.php",
+            };
+        }
+    };
+});

+ 55 - 0
public/assets/v1/common/lib/tinymce/plugins/ax_wordlimit/plugin.min.js

@@ -0,0 +1,55 @@
+tinymce.PluginManager.add('ax_wordlimit', function(editor) {
+    var pluginName='字数限制';
+    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
+    var ax_wordlimit_type = editor.getParam('ax_wordlimit_type', 'letter' );
+    var ax_wordlimit_num = editor.getParam('ax_wordlimit_num', false );
+    var ax_wordlimit_delay = editor.getParam('ax_wordlimit_delay', 500 );
+    var ax_wordlimit_callback = editor.getParam('ax_wordlimit_callback', function(){} );
+    var ax_wordlimit_event = editor.getParam('ax_wordlimit_event', 'SetContent Undo Redo Keyup' );
+    var onsign=1;
+    //统计方法1:计算总字符数
+    var sumLetter = function(){
+        var html = editor.getContent();
+        var re1 = new RegExp("<.+?>","g");
+        var txt = html.replace(re1,'');
+        txt = txt.replace(/\n/g,'');
+        txt = txt.replace(/&nbsp;/g,' ');
+        var num=txt.length;
+        return {txt:txt,num:num}
+    }
+    var onAct = function(){
+        if(onsign){
+            onsign=0;
+            //此处预留更多统计方法
+            switch(ax_wordlimit_type){
+                case 'letter':
+                default:
+                    var res = sumLetter();
+            }
+            if( res.num > ax_wordlimit_num ){
+                ax_wordlimit_callback(editor, res.txt, ax_wordlimit_num);
+            }
+            setTimeout(function(){onsign=1}, ax_wordlimit_delay);
+        }
+        
+    }
+    var setup = function(){
+        if( ax_wordlimit_num>0 ){
+            global$2.setEditorTimeout(editor, function(){
+                var doth = editor.on(ax_wordlimit_event, onAct);
+            }, 300);
+        }
+    };
+
+    setup();
+
+    return {
+        getMetadata: function () {
+            return  {
+                name: pluginName,
+                url: "http://tinymce.ax-z.cn/more-plugins/ax_wordlimit.php",
+            };
+        }
+    };
+});

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/bbcode/plugin.min.js


+ 79 - 0
public/assets/v1/common/lib/tinymce/plugins/bdmap/bd.html

@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>百度地图API自定义地图</title>
+<style>
+	html,body{margin:0;padding:0;}
+	.iw_poi_title {color:#CC5522;font-size:14px;font-weight:bold;overflow:hidden;padding-right:13px;white-space:nowrap}
+	.iw_poi_content {font:12px arial,sans-serif;overflow:visible;padding-top:4px;white-space:-moz-pre-wrap;word-wrap:break-word}
+</style>
+<script src="//api.map.baidu.com/api?key=&v=1.1&services=true"></script>
+</head>
+
+<body onload="initMap();">
+  <!--百度地图容器-->
+  <div style="width:697px;height:550px;border:#ccc solid 1px;" id="dituContent"></div>
+</body>
+<script>
+	function getParam(name) {
+		return location.href.match(new RegExp('[?&]' + name + '=([^?&]+)', 'i')) ? decodeURIComponent(RegExp.$1) : '';
+	}
+	var centerParam = getParam('center');
+	var zoomParam = getParam('zoom');
+	var widthParam = getParam('width');
+	var heightParam = getParam('height');
+	var markersParam = getParam('center');
+
+	//创建和初始化地图函数:
+	function initMap(){
+		// [FF]切换模式后报错
+		if (!window.BMap) {
+			return;
+		}
+		var dituContent = document.getElementById('dituContent');
+		dituContent.style.width = widthParam + 'px';
+		dituContent.style.height = heightParam + 'px';
+
+		createMap();//创建地图
+		setMapEvent();//设置地图事件
+		addMapControl();//向地图添加控件
+
+		// 创建标注
+		var markersArr = markersParam.split(',');
+		var point = new BMap.Point(markersArr[0], markersArr[1]);
+		var marker = new BMap.Marker(point);
+		map.addOverlay(marker); // 将标注添加到地图中
+	}
+
+	//创建地图函数:
+	function createMap(){
+		var map = new BMap.Map("dituContent");//在百度地图容器中创建一个地图
+		var centerArr = centerParam.split(',');
+		var point = new BMap.Point(centerArr[0], centerArr[1]);//定义一个中心点坐标
+		map.centerAndZoom(point, zoomParam);//设定地图的中心点和坐标并将地图显示在地图容器中
+		window.map = map;//将map变量存储在全局
+	}
+
+	//地图事件设置函数:
+	function setMapEvent(){
+		map.enableDragging();//启用地图拖拽事件,默认启用(可不写)
+		//map.enableScrollWheelZoom();//启用地图滚轮放大缩小
+		map.enableDoubleClickZoom();//启用鼠标双击放大,默认启用(可不写)
+		map.enableKeyboard();//启用键盘上下左右键移动地图
+	}
+
+	//地图控件添加函数:
+	function addMapControl(){
+		//向地图中添加缩放控件
+		var ctrl_nav = new BMap.NavigationControl({anchor:BMAP_ANCHOR_TOP_LEFT,type:BMAP_NAVIGATION_CONTROL_LARGE});
+		map.addControl(ctrl_nav);
+		//向地图中添加缩略图控件
+		//var ctrl_ove = new BMap.OverviewMapControl({anchor:BMAP_ANCHOR_BOTTOM_RIGHT,isOpen:1});
+		//map.addControl(ctrl_ove);
+		//向地图中添加比例尺控件
+		var ctrl_sca = new BMap.ScaleControl({anchor:BMAP_ANCHOR_BOTTOM_LEFT});
+		map.addControl(ctrl_sca);
+	}
+</script>
+</html>

+ 124 - 0
public/assets/v1/common/lib/tinymce/plugins/bdmap/map.html

@@ -0,0 +1,124 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Baidu Maps</title>
+<style>
+	html { height:100%; }
+	body { height:100%;margin:0;padding:0;background-color:#fff; }
+	#search_box{position:fixed;top:5px;right:5px;z-index:9999;}
+	#search_box input{
+		-webkit-appearance: none;
+		border-radius:3px;
+		box-sizing:border-box;
+		outline:0;
+		box-shadow:0 0 3px rgba(0,0,0,0.4);
+	}
+	#search_box input[type="text"]{
+		background-color:#fff;
+		border:1px solid #ccc;
+		color:#000;
+		width:180px;
+		padding:5px;
+		font-size:16px;
+		opacity:0.7;
+		box-shadow:0 0 3px rgba(0,0,0,0.4);
+	}
+	#search_box input[type="button"]{
+		margin-left:5px;
+		background-color:#207ab7;
+		border:1px solid #207ab7;
+		color:#fff;
+		padding:4px 6px;
+		font-size:14px;
+	}
+</style>
+<script charset="utf-8" src="http://api.map.baidu.com/api?v=3.0&ak=ONwdanPtvCDLHBSm184T2ynP"></script>
+<script>
+	var editor=parent.tinymce.activeEditor;
+	function insCnt(txt){
+	    editor.insertContent(txt);
+	    parent.tinymce.activeEditor.windowManager.close();
+	}
+
+	var map, geocoder;
+	var lng,lat;
+	function initialize() {
+		map = new BMap.Map('map_canvas');
+		var point = new BMap.Point(116.331398,39.897445);
+		map.centerAndZoom(point, 14);
+		map.addControl(new BMap.NavigationControl());
+		//map.enableScrollWheelZoom();
+
+		//根据IP定位
+		var myCity = new BMap.LocalCity();
+		myCity.get(function(result){map.setCenter(result.name);});
+
+		//浏览器定位,位置更准确,但需要弹出确认,扰民弃用
+		/*var gl = new BMap.Geolocation();
+		gl.getCurrentPosition(function(r){
+			if(this.getStatus() == BMAP_STATUS_SUCCESS){
+				var mk = new BMap.Marker(r.point);
+				map.addOverlay(mk);
+				map.panTo(r.point);
+			}else {
+				//alert('failed'+this.getStatus());
+			}        
+		},{enableHighAccuracy: true})*/
+
+		var gc = new BMap.Geocoder();
+		gc.getLocation(point, function(rs){
+			var addComp = rs.addressComponents;
+			var address = [addComp.city].join('');
+			//console.log(address);
+		});
+
+		map.addEventListener('click',function(e){
+			//alert(e.point.lng + "," + e.point.lat);
+			lng=e.point.lng;
+			lat=e.point.lat;
+			var marker = new BMap.Marker(new BMap.Point(e.point.lng, e.point.lat));
+			map.clearOverlays();
+			map.addOverlay(marker);
+			//insCnt(lng+','+lat);
+			parent.tinymceLng=lng;
+			parent.tinymceLat=lat;
+		});
+
+		document.getElementById('kw').addEventListener('keypress',function(e){
+			if(e.keyCode=='13'){
+				e.preventDefault();
+				searchByStationName();
+			}
+		});
+	}
+
+	function searchByStationName() {
+		var localSearch = new BMap.LocalSearch(map);
+    	//localSearch.enableAutoViewport(); //允许自动调节窗体大小
+		map.clearOverlays();//清空原来的标注
+		var keyword = document.getElementById("kw").value;
+		localSearch.setSearchCompleteCallback(function (searchResult) {
+			console.log(searchResult);
+			if(searchResult.Qq.length==0){
+				alert('搜索不到该地区');
+				return false;
+			}
+			var poi = searchResult.getPoi(0);
+			map.centerAndZoom(poi.point, 14);
+			var marker = new BMap.Marker(new BMap.Point(poi.point.lng, poi.point.lat));
+			parent.tinymceLng=poi.point.lng;
+			parent.tinymceLat=poi.point.lat;
+			map.addOverlay(marker);
+		});
+		localSearch.search(keyword);
+		return false;
+	}
+
+</script>
+</head>
+<body onload="initialize();">
+	<div id="search_box"><input id="kw" type="text" value="" autocomplete="off" placeholder="输入要搜索的地点" /><input type="button" value="搜索" onclick="searchByStationName()"></div>
+	<div id="map_canvas" style="width:100%; height:100%"></div>
+</body>
+</html>

+ 70 - 0
public/assets/v1/common/lib/tinymce/plugins/bdmap/plugin.js

@@ -0,0 +1,70 @@
+tinymce.PluginManager.add('bdmap', function(editor, url) {
+	var pluginName='插入百度地图';
+	var baseURL=tinymce.baseURL;
+	var iframe1 = baseURL+'/plugins/bdmap/map.html';
+	var bdmap_width = function (editor) {
+		return editor.getParam('bdmap_width', 560);
+    };
+    var bdmap_height = function (editor) {
+		return editor.getParam('bdmap_height', 362);
+    };
+	window.tinymceLng='';
+	window.tinymceLat='';
+	var openDialog = function() {
+		return editor.windowManager.openUrl({
+			title: pluginName,
+			size: 'large',
+			//width: 800,
+			//height: 500,
+			url:iframe1,
+			buttons: [
+				{
+					type: 'cancel',
+					text: 'Close'
+				},
+				{
+					type: 'custom',
+					text: 'Save',
+					name: 'save',
+					primary: true
+				},
+			],
+			onAction: function (api, details) {
+				switch (details.name) {
+					case 'save':
+						html='<iframe src="'+baseURL+'/plugins/bdmap/bd.html?center='+tinymceLng+'%2C'+tinymceLat+'&zoom=14&width='+(bdmap_width(editor)-2)+'&height='+(bdmap_height(editor)-2)+'" frameborder="0" style="width:'+bdmap_width(editor)+'px;height:'+bdmap_height(editor)+'px;">';
+						editor.insertContent(html);
+						api.close();
+						break;
+					default:
+						break;
+				}
+				
+			}
+		});
+	};
+
+	editor.ui.registry.getAll().icons.bdmap || editor.ui.registry.addIcon('bdmap','<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M670.8,733c21.1-46.1,45.6-73.7,64.5-90.5,10.3-9.2,21.1-16.8,32.5-21.7-6-8.1-10.6-15.3-15.2-22.2-8.4-12.6-17.3-27.1-21.7-34.1-28.7,15.7-55.9,48.2-77.5,77-12.5,16.7-23.8,34.7-34.7,53.7l52,37.9zM450.2,803.5c6,14.6,9.2,29.3,13.5,40.6,1.6,7.1,3.2,13.5,5.4,19.5,19.5-6,39-12,58-20.1,32.5-13.6,71-33,95.4-58.5l-45-48.2c-8.1,8.1-17.9,14.7-30.4,22.8-21.1,13.6-51.5,30.4-97,43.9zM373.8,204.1c0-52,43.4-95.4,95.4-95.4,53.7,0,94.8,43.4,94.8,95.4,0,53.6-41.2,95.4-94.8,95.4-52,0-95.4-41.7-95.4-95.4zm-105.7,0c0,20.1,2.7,39.6,8.7,58.5h-2.2c16.8,39,35.8,79.9,52,111.1l27.1,52c47.5,91.2,105.7,191.3,114.3,204.3,1.1,0,0.547,0,1.1,1.1,32.5-54.7,60.6-104.1,81.8-143.6l34.1-63.4,26.6-52c15.8-30.9,34.7-71,51.5-110.6h-1.6c6-19,8.7-38.5,8.7-58.5,0-110.6-90.5-200.5-201.1-200.5-111.1,0-201.1,90-201.1,200.5zM229.6,800.2c15.2,11.4,31.3,21.3,48.2,30.4,30.2,16,68.8,34.1,112.7,40.7,1.6-13.1,2.5-29.9,4.3-42.3l3.3-21.7c-11.9-2.2-25.6-5.6-40.1-10.8-24.5-8.8-55.8-23.8-90.5-48.2-9.2,13.5-18.6,25.7-26,35.8l-11.9,16.3zM17.2,949.8c0,41.2,33.6,74.2,74.2,74.2H932.5a74,74,0,0,0,74.2-74.2V336.9A74,74,0,0,0,932.5,262.6H728.2L692.4,362.9H894.6c9.2,0,15.7,6,15.7,15.2V511.4c-28.7-0.531-73.2,2.2-116.5,23.3l5.4,14.6,17.3,45c25.5-8.1,47.7-14.2,65-16.8l28.7-4.3V911.9c0,9.2-6.5,15.1-15.7,15.1H133.2c-9.2,0-15.7-5.9-15.7-15.1V704.8a261.1,261.1,0,0,0,15.2,14.1c9.3,8,23.3,21.1,41.2,36.3,10.3-9.2,20-21.2,28.2-29.8,4.8-5,9.2-9.8,13-14.6-42.8-35.8-86.2-86.2-97.5-100.3V378c0-8.7,6.5-15.2,15.7-15.2h53L209.5,262.5H91.4c-40.7,0-74.2,33.1-74.2,74.3V949.7z"/></svg>');
+	
+	editor.ui.registry.addButton('bdmap', {
+		icon: 'bdmap',
+        tooltip: pluginName,
+		onAction: function() {
+			openDialog();
+		}
+	});
+	editor.ui.registry.addMenuItem('bdmap', {
+		text: pluginName,
+		onAction: function() {
+			openDialog();
+		}
+	});
+	return {
+		getMetadata: function() {
+			return  {
+				name: pluginName,
+				url: "http://tinymce.ax-z.cn/more-plugins/bdmap.php",
+			};
+		}
+	};
+});

+ 70 - 0
public/assets/v1/common/lib/tinymce/plugins/bdmap/plugin.min.js

@@ -0,0 +1,70 @@
+tinymce.PluginManager.add('bdmap', function(editor, url) {
+    var pluginName='插入百度地图';
+    var baseURL=tinymce.baseURL;
+    var iframe1 = baseURL+'/plugins/bdmap/map.html';
+    var bdmap_width = function (editor) {
+        return editor.getParam('bdmap_width', 560);
+    };
+    var bdmap_height = function (editor) {
+        return editor.getParam('bdmap_height', 362);
+    };
+    window.tinymceLng='';
+    window.tinymceLat='';
+    var openDialog = function() {
+        return editor.windowManager.openUrl({
+            title: pluginName,
+            size: 'large',
+            //width: 800,
+            //height: 500,
+            url:iframe1,
+            buttons: [
+                {
+                    type: 'cancel',
+                    text: 'Close'
+                },
+                {
+                    type: 'custom',
+                    text: 'Save',
+                    name: 'save',
+                    primary: true
+                },
+            ],
+            onAction: function (api, details) {
+                switch (details.name) {
+                    case 'save':
+                        html='<iframe src="'+baseURL+'/plugins/bdmap/bd.html?center='+tinymceLng+'%2C'+tinymceLat+'&zoom=14&width='+(bdmap_width(editor)-2)+'&height='+(bdmap_height(editor)-2)+'" frameborder="0" style="width:'+bdmap_width(editor)+'px;height:'+bdmap_height(editor)+'px;">';
+                        editor.insertContent(html);
+                        api.close();
+                        break;
+                    default:
+                        break;
+                }
+                
+            }
+        });
+    };
+
+    editor.ui.registry.getAll().icons.bdmap || editor.ui.registry.addIcon('bdmap','<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M670.8,733c21.1-46.1,45.6-73.7,64.5-90.5,10.3-9.2,21.1-16.8,32.5-21.7-6-8.1-10.6-15.3-15.2-22.2-8.4-12.6-17.3-27.1-21.7-34.1-28.7,15.7-55.9,48.2-77.5,77-12.5,16.7-23.8,34.7-34.7,53.7l52,37.9zM450.2,803.5c6,14.6,9.2,29.3,13.5,40.6,1.6,7.1,3.2,13.5,5.4,19.5,19.5-6,39-12,58-20.1,32.5-13.6,71-33,95.4-58.5l-45-48.2c-8.1,8.1-17.9,14.7-30.4,22.8-21.1,13.6-51.5,30.4-97,43.9zM373.8,204.1c0-52,43.4-95.4,95.4-95.4,53.7,0,94.8,43.4,94.8,95.4,0,53.6-41.2,95.4-94.8,95.4-52,0-95.4-41.7-95.4-95.4zm-105.7,0c0,20.1,2.7,39.6,8.7,58.5h-2.2c16.8,39,35.8,79.9,52,111.1l27.1,52c47.5,91.2,105.7,191.3,114.3,204.3,1.1,0,0.547,0,1.1,1.1,32.5-54.7,60.6-104.1,81.8-143.6l34.1-63.4,26.6-52c15.8-30.9,34.7-71,51.5-110.6h-1.6c6-19,8.7-38.5,8.7-58.5,0-110.6-90.5-200.5-201.1-200.5-111.1,0-201.1,90-201.1,200.5zM229.6,800.2c15.2,11.4,31.3,21.3,48.2,30.4,30.2,16,68.8,34.1,112.7,40.7,1.6-13.1,2.5-29.9,4.3-42.3l3.3-21.7c-11.9-2.2-25.6-5.6-40.1-10.8-24.5-8.8-55.8-23.8-90.5-48.2-9.2,13.5-18.6,25.7-26,35.8l-11.9,16.3zM17.2,949.8c0,41.2,33.6,74.2,74.2,74.2H932.5a74,74,0,0,0,74.2-74.2V336.9A74,74,0,0,0,932.5,262.6H728.2L692.4,362.9H894.6c9.2,0,15.7,6,15.7,15.2V511.4c-28.7-0.531-73.2,2.2-116.5,23.3l5.4,14.6,17.3,45c25.5-8.1,47.7-14.2,65-16.8l28.7-4.3V911.9c0,9.2-6.5,15.1-15.7,15.1H133.2c-9.2,0-15.7-5.9-15.7-15.1V704.8a261.1,261.1,0,0,0,15.2,14.1c9.3,8,23.3,21.1,41.2,36.3,10.3-9.2,20-21.2,28.2-29.8,4.8-5,9.2-9.8,13-14.6-42.8-35.8-86.2-86.2-97.5-100.3V378c0-8.7,6.5-15.2,15.7-15.2h53L209.5,262.5H91.4c-40.7,0-74.2,33.1-74.2,74.3V949.7z"/></svg>');
+    
+    editor.ui.registry.addButton('bdmap', {
+        icon: 'bdmap',
+        tooltip: pluginName,
+        onAction: function() {
+            openDialog();
+        }
+    });
+    editor.ui.registry.addMenuItem('bdmap', {
+        text: pluginName,
+        onAction: function() {
+            openDialog();
+        }
+    });
+    return {
+        getMetadata: function() {
+            return  {
+                name: pluginName,
+                url: "http://tinymce.ax-z.cn/more-plugins/bdmap.php",
+            };
+        }
+    };
+});

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/charmap/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/code/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),o=function(o){var e=o.getContent({source_view:!0});o.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:e},onSubmit:function(e){var t,n;t=o,n=e.getData().code,t.focus(),t.undoManager.transact(function(){t.setContent(n)}),t.selection.setCursorLocation(),t.nodeChanged(),e.close()}})};e.add("code",function(e){var t,n;return(t=e).addCommand("mceCodeEditor",function(){o(t)}),(n=e).ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:function(){return o(n)}}),n.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:function(){return o(n)}}),{}})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/codesample/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/colorpicker/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("colorpicker",function(){console.warn("Color picker plugin is now built in to the core editor, please remove it from your editor configuration")})}();

+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/contextmenu/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("contextmenu",function(){console.warn("Context menu plugin is now built in to the core editor, please remove it from your editor configuration")})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/directionality/plugin.min.js


+ 9424 - 0
public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojiimages.js

@@ -0,0 +1,9424 @@
+// Source: npm package: emojilib
+// Images provided by twemoji: https://github.com/twitter/twemoji
+window.tinymce.Resource.add("tinymce.plugins.emoticons", {
+  100: {
+    keywords: [ "score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcaf" src="1f4af.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  1234: {
+    keywords: [ "numbers", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd22" src="1f522.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  grinning: {
+    keywords: [ "face", "smile", "happy", "joy", ":D", "grin" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude00" src="1f600.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  grimacing: {
+    keywords: [ "face", "grimace", "teeth" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2c" src="1f62c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  grin: {
+    keywords: [ "face", "happy", "smile", "joy", "kawaii" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude01" src="1f601.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  joy: {
+    keywords: [ "face", "cry", "tears", "weep", "happy", "happytears", "haha" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude02" src="1f602.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rofl: {
+    keywords: [ "face", "rolling", "floor", "laughing", "lol", "haha" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd23" src="1f923.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  partying: {
+    keywords: [ "face", "celebration", "woohoo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd73" src="1f973.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiley: {
+    keywords: [ "face", "happy", "joy", "haha", ":D", ":)", "smile", "funny" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude03" src="1f603.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smile: {
+    keywords: [ "face", "happy", "joy", "funny", "haha", "laugh", "like", ":D", ":)" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude04" src="1f604.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sweat_smile: {
+    keywords: [ "face", "hot", "happy", "laugh", "sweat", "smile", "relief" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude05" src="1f605.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  laughing: {
+    keywords: [ "happy", "joy", "lol", "satisfied", "haha", "face", "glad", "XD", "laugh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude06" src="1f606.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  innocent: {
+    keywords: [ "face", "angel", "heaven", "halo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude07" src="1f607.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  wink: {
+    keywords: [ "face", "happy", "mischievous", "secret", ";)", "smile", "eye" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude09" src="1f609.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  blush: {
+    keywords: [ "face", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0a" src="1f60a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  slightly_smiling_face: {
+    keywords: [ "face", "smile" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude42" src="1f642.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  upside_down_face: {
+    keywords: [ "face", "flipped", "silly", "smile" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude43" src="1f643.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  relaxed: {
+    keywords: [ "face", "blush", "massage", "happiness" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u263a\ufe0f" src="263a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  yum: {
+    keywords: [ "happy", "joy", "tongue", "smile", "face", "silly", "yummy", "nom", "delicious", "savouring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0b" src="1f60b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  relieved: {
+    keywords: [ "face", "relaxed", "phew", "massage", "happiness" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0c" src="1f60c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  heart_eyes: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "crush", "heart" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0d" src="1f60d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiling_face_with_three_hearts: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "crush", "hearts", "adore" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd70" src="1f970.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_heart: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude18" src="1f618.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing: {
+    keywords: [ "love", "like", "face", "3", "valentines", "infatuation", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude17" src="1f617.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_smiling_eyes: {
+    keywords: [ "face", "affection", "valentines", "infatuation", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude19" src="1f619.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_closed_eyes: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1a" src="1f61a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue_winking_eye: {
+    keywords: [ "face", "prank", "childish", "playful", "mischievous", "smile", "wink", "tongue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1c" src="1f61c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zany: {
+    keywords: [ "face", "goofy", "crazy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2a" src="1f92a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  raised_eyebrow: {
+    keywords: [ "face", "distrust", "scepticism", "disapproval", "disbelief", "surprise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd28" src="1f928.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  monocle: {
+    keywords: [ "face", "stuffy", "wealthy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd0" src="1f9d0.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue_closed_eyes: {
+    keywords: [ "face", "prank", "playful", "mischievous", "smile", "tongue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1d" src="1f61d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue: {
+    keywords: [ "face", "prank", "childish", "playful", "mischievous", "smile", "tongue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1b" src="1f61b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  money_mouth_face: {
+    keywords: [ "face", "rich", "dollar", "money" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd11" src="1f911.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  nerd_face: {
+    keywords: [ "face", "nerdy", "geek", "dork" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd13" src="1f913.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sunglasses: {
+    keywords: [ "face", "cool", "smile", "summer", "beach", "sunglass" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0e" src="1f60e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  star_struck: {
+    keywords: [ "face", "smile", "starry", "eyes", "grinning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd29" src="1f929.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  clown_face: {
+    keywords: [ "face" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd21" src="1f921.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cowboy_hat_face: {
+    keywords: [ "face", "cowgirl", "hat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd20" src="1f920.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hugs: {
+    keywords: [ "face", "smile", "hug" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd17" src="1f917.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smirk: {
+    keywords: [ "face", "smile", "mean", "prank", "smug", "sarcasm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude0f" src="1f60f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  no_mouth: {
+    keywords: [ "face", "hellokitty" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude36" src="1f636.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  neutral_face: {
+    keywords: [ "indifference", "meh", ":|", "neutral" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude10" src="1f610.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  expressionless: {
+    keywords: [ "face", "indifferent", "-_-", "meh", "deadpan" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude11" src="1f611.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  unamused: {
+    keywords: [ "indifference", "bored", "straight face", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "side_eye" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude12" src="1f612.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  roll_eyes: {
+    keywords: [ "face", "eyeroll", "frustrated" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude44" src="1f644.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  thinking: {
+    keywords: [ "face", "hmmm", "think", "consider" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd14" src="1f914.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  lying_face: {
+    keywords: [ "face", "lie", "pinocchio" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd25" src="1f925.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hand_over_mouth: {
+    keywords: [ "face", "whoops", "shock", "surprise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2d" src="1f92d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  shushing: {
+    keywords: [ "face", "quiet", "shhh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2b" src="1f92b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  symbols_over_mouth: {
+    keywords: [ "face", "swearing", "cursing", "cussing", "profanity", "expletive" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2c" src="1f92c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  exploding_head: {
+    keywords: [ "face", "shocked", "mind", "blown" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2f" src="1f92f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  flushed: {
+    keywords: [ "face", "blush", "shy", "flattered" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude33" src="1f633.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  disappointed: {
+    keywords: [ "face", "sad", "upset", "depressed", ":(" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1e" src="1f61e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  worried: {
+    keywords: [ "face", "concern", "nervous", ":(" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude1f" src="1f61f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  angry: {
+    keywords: [ "mad", "face", "annoyed", "frustrated" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude20" src="1f620.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rage: {
+    keywords: [ "angry", "mad", "hate", "despise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude21" src="1f621.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pensive: {
+    keywords: [ "face", "sad", "depressed", "upset" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude14" src="1f614.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  confused: {
+    keywords: [ "face", "indifference", "huh", "weird", "hmmm", ":/" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude15" src="1f615.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  slightly_frowning_face: {
+    keywords: [ "face", "frowning", "disappointed", "sad", "upset" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude41" src="1f641.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  frowning_face: {
+    keywords: [ "face", "sad", "upset", "frown" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2639" src="2639.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  persevere: {
+    keywords: [ "face", "sick", "no", "upset", "oops" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude23" src="1f623.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  confounded: {
+    keywords: [ "face", "confused", "sick", "unwell", "oops", ":S" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude16" src="1f616.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tired_face: {
+    keywords: [ "sick", "whine", "upset", "frustrated" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2b" src="1f62b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  weary: {
+    keywords: [ "face", "tired", "sleepy", "sad", "frustrated", "upset" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude29" src="1f629.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pleading: {
+    keywords: [ "face", "begging", "mercy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd7a" src="1f97a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  triumph: {
+    keywords: [ "face", "gas", "phew", "proud", "pride" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude24" src="1f624.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  open_mouth: {
+    keywords: [ "face", "surprise", "impressed", "wow", "whoa", ":O" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2e" src="1f62e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scream: {
+    keywords: [ "face", "munch", "scared", "omg" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude31" src="1f631.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  fearful: {
+    keywords: [ "face", "scared", "terrified", "nervous", "oops", "huh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude28" src="1f628.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cold_sweat: {
+    keywords: [ "face", "nervous", "sweat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude30" src="1f630.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hushed: {
+    keywords: [ "face", "woo", "shh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2f" src="1f62f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  frowning: {
+    keywords: [ "face", "aw", "what" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude26" src="1f626.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  anguished: {
+    keywords: [ "face", "stunned", "nervous" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude27" src="1f627.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cry: {
+    keywords: [ "face", "tears", "sad", "depressed", "upset", ":'(" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude22" src="1f622.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  disappointed_relieved: {
+    keywords: [ "face", "phew", "sweat", "nervous" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude25" src="1f625.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  drooling_face: {
+    keywords: [ "face" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd24" src="1f924.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sleepy: {
+    keywords: [ "face", "tired", "rest", "nap" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2a" src="1f62a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sweat: {
+    keywords: [ "face", "hot", "sad", "tired", "exercise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude13" src="1f613.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hot: {
+    keywords: [ "face", "feverish", "heat", "red", "sweating" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd75" src="1f975.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cold: {
+    keywords: [ "face", "blue", "freezing", "frozen", "frostbite", "icicles" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd76" src="1f976.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sob: {
+    keywords: [ "face", "cry", "tears", "sad", "upset", "depressed" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude2d" src="1f62d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dizzy_face: {
+    keywords: [ "spent", "unconscious", "xox", "dizzy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude35" src="1f635.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  astonished: {
+    keywords: [ "face", "xox", "surprised", "poisoned" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude32" src="1f632.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zipper_mouth_face: {
+    keywords: [ "face", "sealed", "zipper", "secret" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd10" src="1f910.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  nauseated_face: {
+    keywords: [ "face", "vomit", "gross", "green", "sick", "throw up", "ill" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd22" src="1f922.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sneezing_face: {
+    keywords: [ "face", "gesundheit", "sneeze", "sick", "allergy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd27" src="1f927.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  vomiting: {
+    keywords: [ "face", "sick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd2e" src="1f92e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mask: {
+    keywords: [ "face", "sick", "ill", "disease" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude37" src="1f637.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  face_with_thermometer: {
+    keywords: [ "sick", "temperature", "thermometer", "cold", "fever" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd12" src="1f912.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  face_with_head_bandage: {
+    keywords: [ "injured", "clumsy", "bandage", "hurt" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd15" src="1f915.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  woozy: {
+    keywords: [ "face", "dizzy", "intoxicated", "tipsy", "wavy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd74" src="1f974.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sleeping: {
+    keywords: [ "face", "tired", "sleepy", "night", "zzz" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude34" src="1f634.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zzz: {
+    keywords: [ "sleepy", "tired", "dream" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca4" src="1f4a4.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  poop: {
+    keywords: [ "hankey", "shitface", "fail", "turd", "shit" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca9" src="1f4a9.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiling_imp: {
+    keywords: [ "devil", "horns" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude08" src="1f608.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  imp: {
+    keywords: [ "devil", "angry", "horns" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7f" src="1f47f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  japanese_ogre: {
+    keywords: [ "monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon", "japanese", "ogre" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc79" src="1f479.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  japanese_goblin: {
+    keywords: [ "red", "evil", "mask", "monster", "scary", "creepy", "japanese", "goblin" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7a" src="1f47a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  skull: {
+    keywords: [ "dead", "skeleton", "creepy", "death" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc80" src="1f480.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ghost: {
+    keywords: [ "halloween", "spooky", "scary" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7b" src="1f47b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  alien: {
+    keywords: [ "UFO", "paul", "weird", "outer_space" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7d" src="1f47d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  robot: {
+    keywords: [ "computer", "machine", "bot" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd16" src="1f916.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiley_cat: {
+    keywords: [ "animal", "cats", "happy", "smile" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3a" src="1f63a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smile_cat: {
+    keywords: [ "animal", "cats", "smile" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude38" src="1f638.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  joy_cat: {
+    keywords: [ "animal", "cats", "haha", "happy", "tears" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude39" src="1f639.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  heart_eyes_cat: {
+    keywords: [ "animal", "love", "like", "affection", "cats", "valentines", "heart" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3b" src="1f63b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smirk_cat: {
+    keywords: [ "animal", "cats", "smirk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3c" src="1f63c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_cat: {
+    keywords: [ "animal", "cats", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3d" src="1f63d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scream_cat: {
+    keywords: [ "animal", "cats", "munch", "scared", "scream" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude40" src="1f640.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  crying_cat_face: {
+    keywords: [ "animal", "tears", "weep", "sad", "cats", "upset", "cry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3f" src="1f63f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pouting_cat: {
+    keywords: [ "animal", "cats" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude3e" src="1f63e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  palms_up: {
+    keywords: [ "hands", "gesture", "cupped", "prayer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd32" src="1f932.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hands: {
+    keywords: [ "gesture", "hooray", "yea", "celebration", "hands" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4c" src="1f64c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  clap: {
+    keywords: [ "hands", "praise", "applause", "congrats", "yay" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4f" src="1f44f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  wave: {
+    keywords: [ "hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4b" src="1f44b.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  call_me_hand: {
+    keywords: [ "hands", "gesture" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd19" src="1f919.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  "+1": {
+    keywords: [ "thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4d" src="1f44d.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  "-1": {
+    keywords: [ "thumbsdown", "no", "dislike", "hand" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4e" src="1f44e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  facepunch: {
+    keywords: [ "angry", "violence", "fist", "hit", "attack", "hand" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4a" src="1f44a.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist: {
+    keywords: [ "fingers", "hand", "grasp" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270a" src="270a.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist_left: {
+    keywords: [ "hand", "fistbump" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1b" src="1f91b.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist_right: {
+    keywords: [ "hand", "fistbump" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1c" src="1f91c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  v: {
+    keywords: [ "fingers", "ohyeah", "hand", "peace", "victory", "two" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270c" src="270c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_hand: {
+    keywords: [ "fingers", "limbs", "perfect", "ok", "okay" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc4c" src="1f44c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hand: {
+    keywords: [ "fingers", "stop", "highfive", "palm", "ban" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270b" src="270b.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_back_of_hand: {
+    keywords: [ "fingers", "raised", "backhand" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1a" src="1f91a.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  open_hands: {
+    keywords: [ "fingers", "butterfly", "hands", "open" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc50" src="1f450.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  muscle: {
+    keywords: [ "arm", "flex", "hand", "summer", "strong", "biceps" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcaa" src="1f4aa.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pray: {
+    keywords: [ "please", "hope", "wish", "namaste", "highfive" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4f" src="1f64f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  foot: {
+    keywords: [ "kick", "stomp" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb6" src="1f9b6.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  leg: {
+    keywords: [ "kick", "limb" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb5" src="1f9b5.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  handshake: {
+    keywords: [ "agreement", "shake" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1d" src="1f91d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  point_up: {
+    keywords: [ "hand", "fingers", "direction", "up" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u261d" src="261d.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_up_2: {
+    keywords: [ "fingers", "hand", "direction", "up" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc46" src="1f446.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_down: {
+    keywords: [ "fingers", "hand", "direction", "down" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc47" src="1f447.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_left: {
+    keywords: [ "direction", "fingers", "hand", "left" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc48" src="1f448.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_right: {
+    keywords: [ "fingers", "hand", "direction", "right" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc49" src="1f449.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fu: {
+    keywords: [ "hand", "fingers", "rude", "middle", "flipping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd95" src="1f595.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hand_with_fingers_splayed: {
+    keywords: [ "hand", "fingers", "palm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd90" src="1f590.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  love_you: {
+    keywords: [ "hand", "fingers", "gesture" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1f" src="1f91f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  metal: {
+    keywords: [ "hand", "fingers", "evil_eye", "sign_of_horns", "rock_on" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd18" src="1f918.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  crossed_fingers: {
+    keywords: [ "good", "lucky" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd1e" src="1f91e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  vulcan_salute: {
+    keywords: [ "hand", "fingers", "spock", "star trek" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd96" src="1f596.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  writing_hand: {
+    keywords: [ "lower_left_ballpoint_pen", "stationery", "write", "compose" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270d" src="270d.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  selfie: {
+    keywords: [ "camera", "phone" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd33" src="1f933.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  nail_care: {
+    keywords: [ "beauty", "manicure", "finger", "fashion", "nail" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc85" src="1f485.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  lips: {
+    keywords: [ "mouth", "kiss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc44" src="1f444.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tooth: {
+    keywords: [ "teeth", "dentist" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb7" src="1f9b7.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tongue: {
+    keywords: [ "mouth", "playful" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc45" src="1f445.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ear: {
+    keywords: [ "face", "hear", "sound", "listen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc42" src="1f442.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  nose: {
+    keywords: [ "smell", "sniff" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc43" src="1f443.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  eye: {
+    keywords: [ "face", "look", "see", "watch", "stare" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc41" src="1f441.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  eyes: {
+    keywords: [ "look", "watch", "stalk", "peek", "see" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc40" src="1f440.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  brain: {
+    keywords: [ "smart", "intelligent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde0" src="1f9e0.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bust_in_silhouette: {
+    keywords: [ "user", "person", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc64" src="1f464.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  busts_in_silhouette: {
+    keywords: [ "user", "person", "human", "group", "team" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc65" src="1f465.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  speaking_head: {
+    keywords: [ "user", "person", "human", "sing", "say", "talk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udde3" src="1f5e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  baby: {
+    keywords: [ "child", "boy", "girl", "toddler" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc76" src="1f476.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  child: {
+    keywords: [ "gender-neutral", "young" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd2" src="1f9d2.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  boy: {
+    keywords: [ "man", "male", "guy", "teenager" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc66" src="1f466.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  girl: {
+    keywords: [ "female", "woman", "teenager" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc67" src="1f467.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  adult: {
+    keywords: [ "gender-neutral", "person" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd1" src="1f9d1.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man: {
+    keywords: [ "mustache", "father", "dad", "guy", "classy", "sir", "moustache" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68" src="1f468.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman: {
+    keywords: [ "female", "girls", "lady" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69" src="1f469.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  blonde_woman: {
+    keywords: [ "woman", "female", "girl", "blonde", "person" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc71\u200d\u2640\ufe0f" src="1f471-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  blonde_man: {
+    keywords: [ "man", "male", "boy", "blonde", "guy", "person" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc71" src="1f471.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bearded_person: {
+    keywords: [ "person", "bewhiskered" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd4" src="1f9d4.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_adult: {
+    keywords: [ "human", "elder", "senior", "gender-neutral" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd3" src="1f9d3.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_man: {
+    keywords: [ "human", "male", "men", "old", "elder", "senior" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc74" src="1f474.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_woman: {
+    keywords: [ "human", "female", "women", "lady", "old", "elder", "senior" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc75" src="1f475.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_with_gua_pi_mao: {
+    keywords: [ "male", "boy", "chinese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc72" src="1f472.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_with_headscarf: {
+    keywords: [ "female", "hijab", "mantilla", "tichel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd5" src="1f9d5.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_with_turban: {
+    keywords: [ "female", "indian", "hinduism", "arabs", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc73\u200d\u2640\ufe0f" src="1f473-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_with_turban: {
+    keywords: [ "male", "indian", "hinduism", "arabs" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc73" src="1f473.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  policewoman: {
+    keywords: [ "woman", "police", "law", "legal", "enforcement", "arrest", "911", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6e\u200d\u2640\ufe0f" src="1f46e-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  policeman: {
+    keywords: [ "man", "police", "law", "legal", "enforcement", "arrest", "911" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6e" src="1f46e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  construction_worker_woman: {
+    keywords: [ "female", "human", "wip", "build", "construction", "worker", "labor", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc77\u200d\u2640\ufe0f" src="1f477-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  construction_worker_man: {
+    keywords: [ "male", "human", "wip", "guy", "build", "construction", "worker", "labor" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc77" src="1f477.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  guardswoman: {
+    keywords: [ "uk", "gb", "british", "female", "royal", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc82\u200d\u2640\ufe0f" src="1f482-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  guardsman: {
+    keywords: [ "uk", "gb", "british", "male", "guy", "royal" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc82" src="1f482.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  female_detective: {
+    keywords: [ "human", "spy", "detective", "female", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd75\ufe0f\u200d\u2640\ufe0f" src="1f575-fe0f-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  male_detective: {
+    keywords: [ "human", "spy", "detective" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd75" src="1f575.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_health_worker: {
+    keywords: [ "doctor", "nurse", "therapist", "healthcare", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\u2695\ufe0f" src="1f469-200d-2695-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_health_worker: {
+    keywords: [ "doctor", "nurse", "therapist", "healthcare", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\u2695\ufe0f" src="1f468-200d-2695-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_farmer: {
+    keywords: [ "rancher", "gardener", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udf3e" src="1f469-200d-1f33e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_farmer: {
+    keywords: [ "rancher", "gardener", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udf3e" src="1f468-200d-1f33e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_cook: {
+    keywords: [ "chef", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udf73" src="1f469-200d-1f373.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_cook: {
+    keywords: [ "chef", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udf73" src="1f468-200d-1f373.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_student: {
+    keywords: [ "graduate", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udf93" src="1f469-200d-1f393.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_student: {
+    keywords: [ "graduate", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udf93" src="1f468-200d-1f393.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_singer: {
+    keywords: [ "rockstar", "entertainer", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udfa4" src="1f469-200d-1f3a4.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_singer: {
+    keywords: [ "rockstar", "entertainer", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udfa4" src="1f468-200d-1f3a4.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_teacher: {
+    keywords: [ "instructor", "professor", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udfeb" src="1f469-200d-1f3eb.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_teacher: {
+    keywords: [ "instructor", "professor", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udfeb" src="1f468-200d-1f3eb.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_factory_worker: {
+    keywords: [ "assembly", "industrial", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udfed" src="1f469-200d-1f3ed.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_factory_worker: {
+    keywords: [ "assembly", "industrial", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udfed" src="1f468-200d-1f3ed.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_technologist: {
+    keywords: [ "coder", "developer", "engineer", "programmer", "software", "woman", "human", "laptop", "computer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udcbb" src="1f469-200d-1f4bb.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_technologist: {
+    keywords: [ "coder", "developer", "engineer", "programmer", "software", "man", "human", "laptop", "computer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udcbb" src="1f468-200d-1f4bb.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_office_worker: {
+    keywords: [ "business", "manager", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udcbc" src="1f469-200d-1f4bc.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_office_worker: {
+    keywords: [ "business", "manager", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udcbc" src="1f468-200d-1f4bc.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_mechanic: {
+    keywords: [ "plumber", "woman", "human", "wrench" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udd27" src="1f469-200d-1f527.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_mechanic: {
+    keywords: [ "plumber", "man", "human", "wrench" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udd27" src="1f468-200d-1f527.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_scientist: {
+    keywords: [ "biologist", "chemist", "engineer", "physicist", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udd2c" src="1f469-200d-1f52c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_scientist: {
+    keywords: [ "biologist", "chemist", "engineer", "physicist", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udd2c" src="1f468-200d-1f52c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_artist: {
+    keywords: [ "painter", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83c\udfa8" src="1f469-200d-1f3a8.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_artist: {
+    keywords: [ "painter", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83c\udfa8" src="1f468-200d-1f3a8.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_firefighter: {
+    keywords: [ "fireman", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\ude92" src="1f469-200d-1f692.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_firefighter: {
+    keywords: [ "fireman", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\ude92" src="1f468-200d-1f692.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_pilot: {
+    keywords: [ "aviator", "plane", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\u2708\ufe0f" src="1f469-200d-2708-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_pilot: {
+    keywords: [ "aviator", "plane", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\u2708\ufe0f" src="1f468-200d-2708-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_astronaut: {
+    keywords: [ "space", "rocket", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\ude80" src="1f469-200d-1f680.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_astronaut: {
+    keywords: [ "space", "rocket", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\ude80" src="1f468-200d-1f680.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_judge: {
+    keywords: [ "justice", "court", "woman", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\u2696\ufe0f" src="1f469-200d-2696-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_judge: {
+    keywords: [ "justice", "court", "man", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\u2696\ufe0f" src="1f468-200d-2696-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_superhero: {
+    keywords: [ "woman", "female", "good", "heroine", "superpowers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb8\u200d\u2640\ufe0f" src="1f9b8-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_superhero: {
+    keywords: [ "man", "male", "good", "hero", "superpowers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb8\u200d\u2642\ufe0f" src="1f9b8-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_supervillain: {
+    keywords: [ "woman", "female", "evil", "bad", "criminal", "heroine", "superpowers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb9\u200d\u2640\ufe0f" src="1f9b9-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_supervillain: {
+    keywords: [ "man", "male", "evil", "bad", "criminal", "hero", "superpowers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb9\u200d\u2642\ufe0f" src="1f9b9-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  mrs_claus: {
+    keywords: [ "woman", "female", "xmas", "mother christmas" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd36" src="1f936.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  santa: {
+    keywords: [ "festival", "man", "male", "xmas", "father christmas" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf85" src="1f385.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  sorceress: {
+    keywords: [ "woman", "female", "mage", "witch" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd9\u200d\u2640\ufe0f" src="1f9d9-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  wizard: {
+    keywords: [ "man", "male", "mage", "sorcerer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd9\u200d\u2642\ufe0f" src="1f9d9-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_elf: {
+    keywords: [ "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddd\u200d\u2640\ufe0f" src="1f9dd-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_elf: {
+    keywords: [ "man", "male" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddd\u200d\u2642\ufe0f" src="1f9dd-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_vampire: {
+    keywords: [ "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddb\u200d\u2640\ufe0f" src="1f9db-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_vampire: {
+    keywords: [ "man", "male", "dracula" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddb\u200d\u2642\ufe0f" src="1f9db-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_zombie: {
+    keywords: [ "woman", "female", "undead", "walking dead" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddf\u200d\u2640\ufe0f" src="1f9df-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  man_zombie: {
+    keywords: [ "man", "male", "dracula", "undead", "walking dead" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddf\u200d\u2642\ufe0f" src="1f9df-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  woman_genie: {
+    keywords: [ "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddde\u200d\u2640\ufe0f" src="1f9de-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  man_genie: {
+    keywords: [ "man", "male" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddde\u200d\u2642\ufe0f" src="1f9de-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mermaid: {
+    keywords: [ "woman", "female", "merwoman", "ariel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddc\u200d\u2640\ufe0f" src="1f9dc-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  merman: {
+    keywords: [ "man", "male", "triton" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udddc\u200d\u2642\ufe0f" src="1f9dc-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_fairy: {
+    keywords: [ "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddda\u200d\u2640\ufe0f" src="1f9da-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_fairy: {
+    keywords: [ "man", "male" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddda\u200d\u2642\ufe0f" src="1f9da-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  angel: {
+    keywords: [ "heaven", "wings", "halo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7c" src="1f47c.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pregnant_woman: {
+    keywords: [ "baby" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd30" src="1f930.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  breastfeeding: {
+    keywords: [ "nursing", "baby" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd31" src="1f931.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  princess: {
+    keywords: [ "girl", "woman", "female", "blond", "crown", "royal", "queen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc78" src="1f478.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  prince: {
+    keywords: [ "boy", "man", "male", "crown", "royal", "king" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd34" src="1f934.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bride_with_veil: {
+    keywords: [ "couple", "marriage", "wedding", "woman", "bride" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc70" src="1f470.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_in_tuxedo: {
+    keywords: [ "couple", "marriage", "wedding", "groom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd35" src="1f935.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  running_woman: {
+    keywords: [ "woman", "walking", "exercise", "race", "running", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc3\u200d\u2640\ufe0f" src="1f3c3-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  running_man: {
+    keywords: [ "man", "walking", "exercise", "race", "running" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc3" src="1f3c3.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  walking_woman: {
+    keywords: [ "human", "feet", "steps", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb6\u200d\u2640\ufe0f" src="1f6b6-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  walking_man: {
+    keywords: [ "human", "feet", "steps" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb6" src="1f6b6.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  dancer: {
+    keywords: [ "female", "girl", "woman", "fun" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc83" src="1f483.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_dancing: {
+    keywords: [ "male", "boy", "fun", "dancer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd7a" src="1f57a.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  dancing_women: {
+    keywords: [ "female", "bunny", "women", "girls" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6f" src="1f46f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dancing_men: {
+    keywords: [ "male", "bunny", "men", "boys" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6f\u200d\u2642\ufe0f" src="1f46f-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple: {
+    keywords: [ "pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6b" src="1f46b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  two_men_holding_hands: {
+    keywords: [ "pair", "couple", "love", "like", "bromance", "friendship", "people", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6c" src="1f46c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  two_women_holding_hands: {
+    keywords: [ "pair", "friendship", "couple", "love", "like", "female", "people", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6d" src="1f46d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bowing_woman: {
+    keywords: [ "woman", "female", "girl" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude47\u200d\u2640\ufe0f" src="1f647-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bowing_man: {
+    keywords: [ "man", "male", "boy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude47" src="1f647.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_facepalming: {
+    keywords: [ "man", "male", "boy", "disbelief" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd26\u200d\u2642\ufe0f" src="1f926-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_facepalming: {
+    keywords: [ "woman", "female", "girl", "disbelief" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd26\u200d\u2640\ufe0f" src="1f926-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_shrugging: {
+    keywords: [ "woman", "female", "girl", "confused", "indifferent", "doubt" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd37" src="1f937.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_shrugging: {
+    keywords: [ "man", "male", "boy", "confused", "indifferent", "doubt" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd37\u200d\u2642\ufe0f" src="1f937-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  tipping_hand_woman: {
+    keywords: [ "female", "girl", "woman", "human", "information" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc81" src="1f481.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  tipping_hand_man: {
+    keywords: [ "male", "boy", "man", "human", "information" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc81\u200d\u2642\ufe0f" src="1f481-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  no_good_woman: {
+    keywords: [ "female", "girl", "woman", "nope" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude45" src="1f645.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  no_good_man: {
+    keywords: [ "male", "boy", "man", "nope" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude45\u200d\u2642\ufe0f" src="1f645-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_woman: {
+    keywords: [ "women", "girl", "female", "pink", "human", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude46" src="1f646.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_man: {
+    keywords: [ "men", "boy", "male", "blue", "human", "man" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude46\u200d\u2642\ufe0f" src="1f646-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raising_hand_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4b" src="1f64b.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raising_hand_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4b\u200d\u2642\ufe0f" src="1f64b-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pouting_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4e" src="1f64e.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pouting_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4e\u200d\u2642\ufe0f" src="1f64e-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  frowning_woman: {
+    keywords: [ "female", "girl", "woman", "sad", "depressed", "discouraged", "unhappy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4d" src="1f64d.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  frowning_man: {
+    keywords: [ "male", "boy", "man", "sad", "depressed", "discouraged", "unhappy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4d\u200d\u2642\ufe0f" src="1f64d-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  haircut_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc87" src="1f487.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  haircut_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc87\u200d\u2642\ufe0f" src="1f487-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  massage_woman: {
+    keywords: [ "female", "girl", "woman", "head" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc86" src="1f486.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  massage_man: {
+    keywords: [ "male", "boy", "man", "head" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc86\u200d\u2642\ufe0f" src="1f486-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_in_steamy_room: {
+    keywords: [ "female", "woman", "spa", "steamroom", "sauna" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd6\u200d\u2640\ufe0f" src="1f9d6-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_in_steamy_room: {
+    keywords: [ "male", "man", "spa", "steamroom", "sauna" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd6\u200d\u2642\ufe0f" src="1f9d6-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  couple_with_heart_woman_man: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc91" src="1f491.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple_with_heart_woman_woman: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc69" src="1f469-200d-2764-fe0f-200d-1f469.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple_with_heart_man_man: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68" src="1f468-200d-2764-fe0f-200d-1f468.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_man_woman: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8f" src="1f48f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_woman_woman: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69" src="1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_man_man: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68" src="1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_boy: {
+    keywords: [ "home", "parents", "child", "mom", "dad", "father", "mother", "people", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc6a" src="1f46a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl: {
+    keywords: [ "home", "parents", "people", "human", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67" src="1f468-200d-1f469-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66" src="1f468-200d-1f469-200d-1f467-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66" src="1f468-200d-1f469-200d-1f466-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67" src="1f468-200d-1f469-200d-1f467-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66" src="1f469-200d-1f469-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67" src="1f469-200d-1f469-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66" src="1f469-200d-1f469-200d-1f467-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66" src="1f469-200d-1f469-200d-1f466-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67" src="1f469-200d-1f469-200d-1f467-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66" src="1f468-200d-1f468-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67" src="1f468-200d-1f468-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66" src="1f468-200d-1f468-200d-1f467-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66" src="1f468-200d-1f468-200d-1f466-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67" src="1f468-200d-1f468-200d-1f467-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_boy: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc66" src="1f469-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc67" src="1f469-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66" src="1f469-200d-1f467-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_boy_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66" src="1f469-200d-1f466-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl_girl: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67" src="1f469-200d-1f467-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_boy: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc66" src="1f468-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc67" src="1f468-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66" src="1f468-200d-1f467-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_boy_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66" src="1f468-200d-1f466-200d-1f466.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl_girl: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67" src="1f468-200d-1f467-200d-1f467.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  yarn: {
+    keywords: [ "ball", "crochet", "knit" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf6" src="1f9f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  thread: {
+    keywords: [ "needle", "sewing", "spool", "string" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf5" src="1f9f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  coat: {
+    keywords: [ "jacket" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde5" src="1f9e5.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  labcoat: {
+    keywords: [ "doctor", "experiment", "scientist", "chemist" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd7c" src="1f97c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  womans_clothes: {
+    keywords: [ "fashion", "shopping_bags", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5a" src="1f45a.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tshirt: {
+    keywords: [ "fashion", "cloth", "casual", "shirt", "tee" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc55" src="1f455.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  jeans: {
+    keywords: [ "fashion", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc56" src="1f456.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  necktie: {
+    keywords: [ "shirt", "suitup", "formal", "fashion", "cloth", "business" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc54" src="1f454.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dress: {
+    keywords: [ "clothes", "fashion", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc57" src="1f457.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bikini: {
+    keywords: [ "swimming", "female", "woman", "girl", "fashion", "beach", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc59" src="1f459.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kimono: {
+    keywords: [ "dress", "fashion", "women", "female", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc58" src="1f458.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  lipstick: {
+    keywords: [ "female", "girl", "fashion", "woman" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc84" src="1f484.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kiss: {
+    keywords: [ "face", "lips", "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8b" src="1f48b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  footprints: {
+    keywords: [ "feet", "tracking", "walking", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc63" src="1f463.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  flat_shoe: {
+    keywords: [ "ballet", "slip-on", "slipper" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd7f" src="1f97f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  high_heel: {
+    keywords: [ "fashion", "shoes", "female", "pumps", "stiletto" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc60" src="1f460.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sandal: {
+    keywords: [ "shoes", "fashion", "flip flops" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc61" src="1f461.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  boot: {
+    keywords: [ "shoes", "fashion" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc62" src="1f462.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mans_shoe: {
+    keywords: [ "fashion", "male" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5e" src="1f45e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  athletic_shoe: {
+    keywords: [ "shoes", "sports", "sneakers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5f" src="1f45f.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hiking_boot: {
+    keywords: [ "backpacking", "camping", "hiking" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd7e" src="1f97e.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  socks: {
+    keywords: [ "stockings", "clothes" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde6" src="1f9e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  gloves: {
+    keywords: [ "hands", "winter", "clothes" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde4" src="1f9e4.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scarf: {
+    keywords: [ "neck", "winter", "clothes" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde3" src="1f9e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  womans_hat: {
+    keywords: [ "fashion", "accessories", "female", "lady", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc52" src="1f452.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tophat: {
+    keywords: [ "magic", "gentleman", "classy", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa9" src="1f3a9.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  billed_hat: {
+    keywords: [ "cap", "baseball" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde2" src="1f9e2.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rescue_worker_helmet: {
+    keywords: [ "construction", "build" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d1" src="26d1.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mortar_board: {
+    keywords: [ "school", "college", "degree", "university", "graduation", "cap", "hat", "legal", "learn", "education" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf93" src="1f393.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  crown: {
+    keywords: [ "king", "kod", "leader", "royalty", "lord" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc51" src="1f451.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  school_satchel: {
+    keywords: [ "student", "education", "bag", "backpack" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf92" src="1f392.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  luggage: {
+    keywords: [ "packing", "travel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf3" src="1f9f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pouch: {
+    keywords: [ "bag", "accessories", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5d" src="1f45d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  purse: {
+    keywords: [ "fashion", "accessories", "money", "sales", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5b" src="1f45b.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  handbag: {
+    keywords: [ "fashion", "accessory", "accessories", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc5c" src="1f45c.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  briefcase: {
+    keywords: [ "business", "documents", "work", "law", "legal", "job", "career" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcbc" src="1f4bc.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  eyeglasses: {
+    keywords: [ "fashion", "accessories", "eyesight", "nerdy", "dork", "geek" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc53" src="1f453.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dark_sunglasses: {
+    keywords: [ "face", "cool", "accessories" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd76" src="1f576.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  goggles: {
+    keywords: [ "eyes", "protection", "safety" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd7d" src="1f97d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ring: {
+    keywords: [ "wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8d" src="1f48d.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  closed_umbrella: {
+    keywords: [ "weather", "rain", "drizzle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf02" src="1f302.png"/>',
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dog: {
+    keywords: [ "animal", "friend", "nature", "woof", "puppy", "pet", "faithful" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc36" src="1f436.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cat: {
+    keywords: [ "animal", "meow", "nature", "pet", "kitten" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc31" src="1f431.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mouse: {
+    keywords: [ "animal", "nature", "cheese_wedge", "rodent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2d" src="1f42d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hamster: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc39" src="1f439.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rabbit: {
+    keywords: [ "animal", "nature", "pet", "spring", "magic", "bunny" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc30" src="1f430.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fox_face: {
+    keywords: [ "animal", "nature", "face" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8a" src="1f98a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bear: {
+    keywords: [ "animal", "nature", "wild" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3b" src="1f43b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  panda_face: {
+    keywords: [ "animal", "nature", "panda" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3c" src="1f43c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  koala: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc28" src="1f428.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tiger: {
+    keywords: [ "animal", "cat", "danger", "wild", "nature", "roar" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2f" src="1f42f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lion: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd81" src="1f981.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cow: {
+    keywords: [ "beef", "ox", "animal", "nature", "moo", "milk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2e" src="1f42e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig: {
+    keywords: [ "animal", "oink", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc37" src="1f437.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig_nose: {
+    keywords: [ "animal", "oink" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3d" src="1f43d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  frog: {
+    keywords: [ "animal", "nature", "croak", "toad" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc38" src="1f438.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  squid: {
+    keywords: [ "animal", "nature", "ocean", "sea" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd91" src="1f991.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  octopus: {
+    keywords: [ "animal", "creature", "ocean", "sea", "nature", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc19" src="1f419.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shrimp: {
+    keywords: [ "animal", "ocean", "nature", "seafood" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd90" src="1f990.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  monkey_face: {
+    keywords: [ "animal", "nature", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc35" src="1f435.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  gorilla: {
+    keywords: [ "animal", "nature", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8d" src="1f98d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  see_no_evil: {
+    keywords: [ "monkey", "animal", "nature", "haha" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude48" src="1f648.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hear_no_evil: {
+    keywords: [ "animal", "monkey", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude49" src="1f649.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  speak_no_evil: {
+    keywords: [ "monkey", "animal", "nature", "omg" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude4a" src="1f64a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  monkey: {
+    keywords: [ "animal", "nature", "banana", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc12" src="1f412.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chicken: {
+    keywords: [ "animal", "cluck", "nature", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc14" src="1f414.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  penguin: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc27" src="1f427.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bird: {
+    keywords: [ "animal", "nature", "fly", "tweet", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc26" src="1f426.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  baby_chick: {
+    keywords: [ "animal", "chicken", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc24" src="1f424.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hatching_chick: {
+    keywords: [ "animal", "chicken", "egg", "born", "baby", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc23" src="1f423.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hatched_chick: {
+    keywords: [ "animal", "chicken", "baby", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc25" src="1f425.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  duck: {
+    keywords: [ "animal", "nature", "bird", "mallard" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd86" src="1f986.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  eagle: {
+    keywords: [ "animal", "nature", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd85" src="1f985.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  owl: {
+    keywords: [ "animal", "nature", "bird", "hoot" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd89" src="1f989.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bat: {
+    keywords: [ "animal", "nature", "blind", "vampire" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd87" src="1f987.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wolf: {
+    keywords: [ "animal", "nature", "wild" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3a" src="1f43a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  boar: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc17" src="1f417.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  horse: {
+    keywords: [ "animal", "brown", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc34" src="1f434.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  unicorn: {
+    keywords: [ "animal", "nature", "mystical" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd84" src="1f984.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  honeybee: {
+    keywords: [ "animal", "insect", "nature", "bug", "spring", "honey" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1d" src="1f41d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bug: {
+    keywords: [ "animal", "insect", "nature", "worm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1b" src="1f41b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  butterfly: {
+    keywords: [ "animal", "insect", "nature", "caterpillar" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8b" src="1f98b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snail: {
+    keywords: [ "slow", "animal", "shell" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0c" src="1f40c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  beetle: {
+    keywords: [ "animal", "insect", "nature", "ladybug" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1e" src="1f41e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ant: {
+    keywords: [ "animal", "insect", "nature", "bug" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1c" src="1f41c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  grasshopper: {
+    keywords: [ "animal", "cricket", "chirp" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd97" src="1f997.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  spider: {
+    keywords: [ "animal", "arachnid" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd77" src="1f577.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  scorpion: {
+    keywords: [ "animal", "arachnid" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd82" src="1f982.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crab: {
+    keywords: [ "animal", "crustacean" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd80" src="1f980.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snake: {
+    keywords: [ "animal", "evil", "nature", "hiss", "python" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0d" src="1f40d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lizard: {
+    keywords: [ "animal", "nature", "reptile" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8e" src="1f98e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  "t-rex": {
+    keywords: [ "animal", "nature", "dinosaur", "tyrannosaurus", "extinct" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd96" src="1f996.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sauropod: {
+    keywords: [ "animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd95" src="1f995.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  turtle: {
+    keywords: [ "animal", "slow", "nature", "tortoise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc22" src="1f422.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tropical_fish: {
+    keywords: [ "animal", "swim", "ocean", "beach", "nemo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc20" src="1f420.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fish: {
+    keywords: [ "animal", "food", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1f" src="1f41f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  blowfish: {
+    keywords: [ "animal", "nature", "food", "sea", "ocean" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc21" src="1f421.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dolphin: {
+    keywords: [ "animal", "nature", "fish", "sea", "ocean", "flipper", "fins", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2c" src="1f42c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shark: {
+    keywords: [ "animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd88" src="1f988.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  whale: {
+    keywords: [ "animal", "nature", "sea", "ocean" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc33" src="1f433.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  whale2: {
+    keywords: [ "animal", "nature", "sea", "ocean" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0b" src="1f40b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crocodile: {
+    keywords: [ "animal", "nature", "reptile", "lizard", "alligator" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0a" src="1f40a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  leopard: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc06" src="1f406.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  zebra: {
+    keywords: [ "animal", "nature", "stripes", "safari" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd93" src="1f993.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tiger2: {
+    keywords: [ "animal", "nature", "roar" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc05" src="1f405.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  water_buffalo: {
+    keywords: [ "animal", "nature", "ox", "cow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc03" src="1f403.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ox: {
+    keywords: [ "animal", "cow", "beef" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc02" src="1f402.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cow2: {
+    keywords: [ "beef", "ox", "animal", "nature", "moo", "milk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc04" src="1f404.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  deer: {
+    keywords: [ "animal", "nature", "horns", "venison" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8c" src="1f98c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dromedary_camel: {
+    keywords: [ "animal", "hot", "desert", "hump" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2a" src="1f42a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  camel: {
+    keywords: [ "animal", "nature", "hot", "desert", "hump" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc2b" src="1f42b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  giraffe: {
+    keywords: [ "animal", "nature", "spots", "safari" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd92" src="1f992.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  elephant: {
+    keywords: [ "animal", "nature", "nose", "th", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc18" src="1f418.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rhinoceros: {
+    keywords: [ "animal", "nature", "horn" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd8f" src="1f98f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  goat: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc10" src="1f410.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ram: {
+    keywords: [ "animal", "sheep", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0f" src="1f40f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sheep: {
+    keywords: [ "animal", "nature", "wool", "shipit" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc11" src="1f411.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  racehorse: {
+    keywords: [ "animal", "gamble", "luck" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc0e" src="1f40e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig2: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc16" src="1f416.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rat: {
+    keywords: [ "animal", "mouse", "rodent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc00" src="1f400.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mouse2: {
+    keywords: [ "animal", "nature", "rodent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc01" src="1f401.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rooster: {
+    keywords: [ "animal", "nature", "chicken" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc13" src="1f413.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  turkey: {
+    keywords: [ "animal", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd83" src="1f983.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dove: {
+    keywords: [ "animal", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd4a" src="1f54a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dog2: {
+    keywords: [ "animal", "nature", "friend", "doge", "pet", "faithful" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc15" src="1f415.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  poodle: {
+    keywords: [ "dog", "animal", "101", "nature", "pet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc29" src="1f429.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cat2: {
+    keywords: [ "animal", "meow", "pet", "cats" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc08" src="1f408.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rabbit2: {
+    keywords: [ "animal", "nature", "pet", "magic", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc07" src="1f407.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chipmunk: {
+    keywords: [ "animal", "nature", "rodent", "squirrel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3f" src="1f43f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hedgehog: {
+    keywords: [ "animal", "nature", "spiny" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd94" src="1f994.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  raccoon: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9d" src="1f99d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  llama: {
+    keywords: [ "animal", "nature", "alpaca" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd99" src="1f999.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hippopotamus: {
+    keywords: [ "animal", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9b" src="1f99b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  kangaroo: {
+    keywords: [ "animal", "nature", "australia", "joey", "hop", "marsupial" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd98" src="1f998.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  badger: {
+    keywords: [ "animal", "nature", "honey" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udda1" src="1f9a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  swan: {
+    keywords: [ "animal", "nature", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udda2" src="1f9a2.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  peacock: {
+    keywords: [ "animal", "nature", "peahen", "bird" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9a" src="1f99a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  parrot: {
+    keywords: [ "animal", "nature", "bird", "pirate", "talk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9c" src="1f99c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lobster: {
+    keywords: [ "animal", "nature", "bisque", "claws", "seafood" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9e" src="1f99e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mosquito: {
+    keywords: [ "animal", "nature", "insect", "malaria" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd9f" src="1f99f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  paw_prints: {
+    keywords: [ "animal", "tracking", "footprints", "dog", "cat", "pet", "feet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc3e" src="1f43e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dragon: {
+    keywords: [ "animal", "myth", "nature", "chinese", "green" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc09" src="1f409.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dragon_face: {
+    keywords: [ "animal", "myth", "nature", "chinese", "green" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc32" src="1f432.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cactus: {
+    keywords: [ "vegetable", "plant", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf35" src="1f335.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  christmas_tree: {
+    keywords: [ "festival", "vacation", "december", "xmas", "celebration" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf84" src="1f384.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  evergreen_tree: {
+    keywords: [ "plant", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf32" src="1f332.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  deciduous_tree: {
+    keywords: [ "plant", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf33" src="1f333.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  palm_tree: {
+    keywords: [ "plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf34" src="1f334.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  seedling: {
+    keywords: [ "plant", "nature", "grass", "lawn", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf31" src="1f331.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  herb: {
+    keywords: [ "vegetable", "plant", "medicine", "weed", "grass", "lawn" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3f" src="1f33f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shamrock: {
+    keywords: [ "vegetable", "plant", "nature", "irish", "clover" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2618" src="2618.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  four_leaf_clover: {
+    keywords: [ "vegetable", "plant", "nature", "lucky", "irish" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf40" src="1f340.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bamboo: {
+    keywords: [ "plant", "nature", "vegetable", "panda", "pine_decoration" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8d" src="1f38d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tanabata_tree: {
+    keywords: [ "plant", "nature", "branch", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8b" src="1f38b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  leaves: {
+    keywords: [ "nature", "plant", "tree", "vegetable", "grass", "lawn", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf43" src="1f343.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fallen_leaf: {
+    keywords: [ "nature", "plant", "vegetable", "leaves" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf42" src="1f342.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  maple_leaf: {
+    keywords: [ "nature", "plant", "vegetable", "ca", "fall" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf41" src="1f341.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ear_of_rice: {
+    keywords: [ "nature", "plant" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3e" src="1f33e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hibiscus: {
+    keywords: [ "plant", "vegetable", "flowers", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3a" src="1f33a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sunflower: {
+    keywords: [ "nature", "plant", "fall" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3b" src="1f33b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rose: {
+    keywords: [ "flowers", "valentines", "love", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf39" src="1f339.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wilted_flower: {
+    keywords: [ "plant", "nature", "flower" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd40" src="1f940.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tulip: {
+    keywords: [ "flowers", "plant", "nature", "summer", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf37" src="1f337.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  blossom: {
+    keywords: [ "nature", "flowers", "yellow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3c" src="1f33c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cherry_blossom: {
+    keywords: [ "nature", "plant", "spring", "flower" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf38" src="1f338.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bouquet: {
+    keywords: [ "flowers", "nature", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc90" src="1f490.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mushroom: {
+    keywords: [ "plant", "vegetable" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf44" src="1f344.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chestnut: {
+    keywords: [ "food", "squirrel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf30" src="1f330.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  jack_o_lantern: {
+    keywords: [ "halloween", "light", "pumpkin", "creepy", "fall" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf83" src="1f383.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shell: {
+    keywords: [ "nature", "sea", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc1a" src="1f41a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  spider_web: {
+    keywords: [ "animal", "insect", "arachnid", "silk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd78" src="1f578.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_americas: {
+    keywords: [ "globe", "world", "USA", "international" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0e" src="1f30e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_africa: {
+    keywords: [ "globe", "world", "international" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0d" src="1f30d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_asia: {
+    keywords: [ "globe", "world", "east", "international" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0f" src="1f30f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  full_moon: {
+    keywords: [ "nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf15" src="1f315.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waning_gibbous_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing_gibbous_moon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf16" src="1f316.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  last_quarter_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf17" src="1f317.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waning_crescent_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf18" src="1f318.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  new_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf11" src="1f311.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waxing_crescent_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf12" src="1f312.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  first_quarter_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf13" src="1f313.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waxing_gibbous_moon: {
+    keywords: [ "nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf14" src="1f314.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  new_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1a" src="1f31a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  full_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1d" src="1f31d.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  first_quarter_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1b" src="1f31b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  last_quarter_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1c" src="1f31c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_with_face: {
+    keywords: [ "nature", "morning", "sky" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1e" src="1f31e.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crescent_moon: {
+    keywords: [ "night", "sleep", "sky", "evening", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf19" src="1f319.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  star: {
+    keywords: [ "night", "yellow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b50" src="2b50.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  star2: {
+    keywords: [ "night", "sparkle", "awesome", "good", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf1f" src="1f31f.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dizzy: {
+    keywords: [ "star", "sparkle", "shoot", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcab" src="1f4ab.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sparkles: {
+    keywords: [ "stars", "shine", "shiny", "cool", "awesome", "good", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2728" src="2728.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  comet: {
+    keywords: [ "space" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2604" src="2604.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sunny: {
+    keywords: [ "weather", "nature", "brightness", "summer", "beach", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2600\ufe0f" src="2600.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_small_cloud: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf24" src="1f324.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  partly_sunny: {
+    keywords: [ "weather", "nature", "cloudy", "morning", "fall", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c5" src="26c5.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_large_cloud: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf25" src="1f325.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_rain_cloud: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf26" src="1f326.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud: {
+    keywords: [ "weather", "sky" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2601\ufe0f" src="2601.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_rain: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf27" src="1f327.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_lightning_and_rain: {
+    keywords: [ "weather", "lightning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c8" src="26c8.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_lightning: {
+    keywords: [ "weather", "thunder" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf29" src="1f329.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  zap: {
+    keywords: [ "thunder", "weather", "lightning bolt", "fast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26a1" src="26a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fire: {
+    keywords: [ "hot", "cook", "flame" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd25" src="1f525.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  boom: {
+    keywords: [ "bomb", "explode", "explosion", "collision", "blown" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca5" src="1f4a5.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowflake: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2744\ufe0f" src="2744.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_snow: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf28" src="1f328.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowman: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas", "frozen", "without_snow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c4" src="26c4.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowman_with_snow: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas", "frozen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2603" src="2603.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wind_face: {
+    keywords: [ "gust", "air" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2c" src="1f32c.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dash: {
+    keywords: [ "wind", "air", "fast", "shoo", "fart", "smoke", "puff" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca8" src="1f4a8.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tornado: {
+    keywords: [ "weather", "cyclone", "twister" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2a" src="1f32a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fog: {
+    keywords: [ "weather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2b" src="1f32b.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  open_umbrella: {
+    keywords: [ "weather", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2602" src="2602.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  umbrella: {
+    keywords: [ "rainy", "weather", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2614" src="2614.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  droplet: {
+    keywords: [ "water", "drip", "faucet", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca7" src="1f4a7.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sweat_drops: {
+    keywords: [ "water", "drip", "oops" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca6" src="1f4a6.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ocean: {
+    keywords: [ "sea", "water", "wave", "nature", "tsunami", "disaster" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0a" src="1f30a.png"/>',
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  green_apple: {
+    keywords: [ "fruit", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4f" src="1f34f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  apple: {
+    keywords: [ "fruit", "mac", "school" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4e" src="1f34e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pear: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf50" src="1f350.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tangerine: {
+    keywords: [ "food", "fruit", "nature", "orange" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4a" src="1f34a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  lemon: {
+    keywords: [ "fruit", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4b" src="1f34b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  banana: {
+    keywords: [ "fruit", "food", "monkey" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4c" src="1f34c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  watermelon: {
+    keywords: [ "fruit", "food", "picnic", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf49" src="1f349.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  grapes: {
+    keywords: [ "fruit", "food", "wine" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf47" src="1f347.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  strawberry: {
+    keywords: [ "fruit", "food", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf53" src="1f353.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  melon: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf48" src="1f348.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cherries: {
+    keywords: [ "food", "fruit" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf52" src="1f352.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  peach: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf51" src="1f351.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pineapple: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf4d" src="1f34d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  coconut: {
+    keywords: [ "fruit", "nature", "food", "palm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd65" src="1f965.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  kiwi_fruit: {
+    keywords: [ "fruit", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5d" src="1f95d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  mango: {
+    keywords: [ "fruit", "food", "tropical" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6d" src="1f96d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  avocado: {
+    keywords: [ "fruit", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd51" src="1f951.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  broccoli: {
+    keywords: [ "fruit", "food", "vegetable" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd66" src="1f966.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tomato: {
+    keywords: [ "fruit", "vegetable", "nature", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf45" src="1f345.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  eggplant: {
+    keywords: [ "vegetable", "nature", "food", "aubergine" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf46" src="1f346.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cucumber: {
+    keywords: [ "fruit", "food", "pickle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd52" src="1f952.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  carrot: {
+    keywords: [ "vegetable", "food", "orange" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd55" src="1f955.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hot_pepper: {
+    keywords: [ "food", "spicy", "chilli", "chili" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf36" src="1f336.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  potato: {
+    keywords: [ "food", "tuber", "vegatable", "starch" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd54" src="1f954.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  corn: {
+    keywords: [ "food", "vegetable", "plant" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf3d" src="1f33d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  leafy_greens: {
+    keywords: [ "food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6c" src="1f96c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sweet_potato: {
+    keywords: [ "food", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf60" src="1f360.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  peanuts: {
+    keywords: [ "food", "nut" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5c" src="1f95c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  honey_pot: {
+    keywords: [ "bees", "sweet", "kitchen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6f" src="1f36f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  croissant: {
+    keywords: [ "food", "bread", "french" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd50" src="1f950.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bread: {
+    keywords: [ "food", "wheat", "breakfast", "toast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5e" src="1f35e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  baguette_bread: {
+    keywords: [ "food", "bread", "french" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd56" src="1f956.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bagel: {
+    keywords: [ "food", "bread", "bakery", "schmear" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6f" src="1f96f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pretzel: {
+    keywords: [ "food", "bread", "twisted" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd68" src="1f968.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cheese: {
+    keywords: [ "food", "chadder" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddc0" src="1f9c0.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  egg: {
+    keywords: [ "food", "chicken", "breakfast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5a" src="1f95a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bacon: {
+    keywords: [ "food", "breakfast", "pork", "pig", "meat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd53" src="1f953.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  steak: {
+    keywords: [ "food", "cow", "meat", "cut", "chop", "lambchop", "porkchop" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd69" src="1f969.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pancakes: {
+    keywords: [ "food", "breakfast", "flapjacks", "hotcakes" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5e" src="1f95e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  poultry_leg: {
+    keywords: [ "food", "meat", "drumstick", "bird", "chicken", "turkey" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf57" src="1f357.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  meat_on_bone: {
+    keywords: [ "good", "food", "drumstick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf56" src="1f356.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bone: {
+    keywords: [ "skeleton" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddb4" src="1f9b4.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fried_shrimp: {
+    keywords: [ "food", "animal", "appetizer", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf64" src="1f364.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fried_egg: {
+    keywords: [ "food", "breakfast", "kitchen", "egg" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf73" src="1f373.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hamburger: {
+    keywords: [ "meat", "fast food", "beef", "cheeseburger", "mcdonalds", "burger king" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf54" src="1f354.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fries: {
+    keywords: [ "chips", "snack", "fast food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5f" src="1f35f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  stuffed_flatbread: {
+    keywords: [ "food", "flatbread", "stuffed", "gyro" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd59" src="1f959.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hotdog: {
+    keywords: [ "food", "frankfurter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2d" src="1f32d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pizza: {
+    keywords: [ "food", "party" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf55" src="1f355.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sandwich: {
+    keywords: [ "food", "lunch", "bread" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6a" src="1f96a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  canned_food: {
+    keywords: [ "food", "soup" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6b" src="1f96b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  spaghetti: {
+    keywords: [ "food", "italian", "noodle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5d" src="1f35d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  taco: {
+    keywords: [ "food", "mexican" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2e" src="1f32e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  burrito: {
+    keywords: [ "food", "mexican" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf2f" src="1f32f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  green_salad: {
+    keywords: [ "food", "healthy", "lettuce" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd57" src="1f957.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  shallow_pan_of_food: {
+    keywords: [ "food", "cooking", "casserole", "paella" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd58" src="1f958.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  ramen: {
+    keywords: [ "food", "japanese", "noodle", "chopsticks" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5c" src="1f35c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  stew: {
+    keywords: [ "food", "meat", "soup" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf72" src="1f372.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fish_cake: {
+    keywords: [ "food", "japan", "sea", "beach", "narutomaki", "pink", "swirl", "kamaboko", "surimi", "ramen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf65" src="1f365.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fortune_cookie: {
+    keywords: [ "food", "prophecy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd60" src="1f960.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sushi: {
+    keywords: [ "food", "fish", "japanese", "rice" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf63" src="1f363.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bento: {
+    keywords: [ "food", "japanese", "box" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf71" src="1f371.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  curry: {
+    keywords: [ "food", "spicy", "hot", "indian" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5b" src="1f35b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice_ball: {
+    keywords: [ "food", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf59" src="1f359.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice: {
+    keywords: [ "food", "china", "asian" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf5a" src="1f35a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice_cracker: {
+    keywords: [ "food", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf58" src="1f358.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  oden: {
+    keywords: [ "food", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf62" src="1f362.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  dango: {
+    keywords: [ "food", "dessert", "sweet", "japanese", "barbecue", "meat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf61" src="1f361.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  shaved_ice: {
+    keywords: [ "hot", "dessert", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf67" src="1f367.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  ice_cream: {
+    keywords: [ "food", "hot", "dessert" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf68" src="1f368.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  icecream: {
+    keywords: [ "food", "hot", "dessert", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf66" src="1f366.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pie: {
+    keywords: [ "food", "dessert", "pastry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd67" src="1f967.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cake: {
+    keywords: [ "food", "dessert" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf70" src="1f370.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cupcake: {
+    keywords: [ "food", "dessert", "bakery", "sweet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddc1" src="1f9c1.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  moon_cake: {
+    keywords: [ "food", "autumn" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd6e" src="1f96e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  birthday: {
+    keywords: [ "food", "dessert", "cake" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf82" src="1f382.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  custard: {
+    keywords: [ "dessert", "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6e" src="1f36e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  candy: {
+    keywords: [ "snack", "dessert", "sweet", "lolly" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6c" src="1f36c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  lollipop: {
+    keywords: [ "food", "snack", "candy", "sweet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6d" src="1f36d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  chocolate_bar: {
+    keywords: [ "food", "snack", "dessert", "sweet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6b" src="1f36b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  popcorn: {
+    keywords: [ "food", "movie theater", "films", "snack" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7f" src="1f37f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  dumpling: {
+    keywords: [ "food", "empanada", "pierogi", "potsticker" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5f" src="1f95f.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  doughnut: {
+    keywords: [ "food", "dessert", "snack", "sweet", "donut" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf69" src="1f369.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cookie: {
+    keywords: [ "food", "snack", "oreo", "chocolate", "sweet", "dessert" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf6a" src="1f36a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  milk_glass: {
+    keywords: [ "beverage", "drink", "cow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd5b" src="1f95b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  beer: {
+    keywords: [ "relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7a" src="1f37a.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  beers: {
+    keywords: [ "relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7b" src="1f37b.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  clinking_glasses: {
+    keywords: [ "beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd42" src="1f942.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  wine_glass: {
+    keywords: [ "drink", "beverage", "drunk", "alcohol", "booze" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf77" src="1f377.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tumbler_glass: {
+    keywords: [ "drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "glass", "shot" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd43" src="1f943.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cocktail: {
+    keywords: [ "drink", "drunk", "alcohol", "beverage", "booze", "mojito" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf78" src="1f378.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tropical_drink: {
+    keywords: [ "beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf79" src="1f379.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  champagne: {
+    keywords: [ "drink", "wine", "bottle", "celebration" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7e" src="1f37e.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sake: {
+    keywords: [ "wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf76" src="1f376.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tea: {
+    keywords: [ "drink", "bowl", "breakfast", "green", "british" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf75" src="1f375.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cup_with_straw: {
+    keywords: [ "drink", "soda" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd64" src="1f964.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  coffee: {
+    keywords: [ "beverage", "caffeine", "latte", "espresso" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2615" src="2615.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  baby_bottle: {
+    keywords: [ "food", "container", "milk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7c" src="1f37c.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  salt: {
+    keywords: [ "condiment", "shaker" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddc2" src="1f9c2.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  spoon: {
+    keywords: [ "cutlery", "kitchen", "tableware" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd44" src="1f944.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fork_and_knife: {
+    keywords: [ "cutlery", "kitchen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf74" src="1f374.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  plate_with_cutlery: {
+    keywords: [ "food", "eat", "meal", "lunch", "dinner", "restaurant" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf7d" src="1f37d.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bowl_with_spoon: {
+    keywords: [ "food", "breakfast", "cereal", "oatmeal", "porridge" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd63" src="1f963.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  takeout_box: {
+    keywords: [ "food", "leftovers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd61" src="1f961.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  chopsticks: {
+    keywords: [ "food" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd62" src="1f962.png"/>',
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  soccer: {
+    keywords: [ "sports", "football" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26bd" src="26bd.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  basketball: {
+    keywords: [ "sports", "balls", "NBA" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc0" src="1f3c0.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  football: {
+    keywords: [ "sports", "balls", "NFL" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc8" src="1f3c8.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  baseball: {
+    keywords: [ "sports", "balls" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26be" src="26be.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  softball: {
+    keywords: [ "sports", "balls" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4e" src="1f94e.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  tennis: {
+    keywords: [ "sports", "balls", "green" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfbe" src="1f3be.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  volleyball: {
+    keywords: [ "sports", "balls" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd0" src="1f3d0.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rugby_football: {
+    keywords: [ "sports", "team" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc9" src="1f3c9.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  flying_disc: {
+    keywords: [ "sports", "frisbee", "ultimate" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4f" src="1f94f.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "8ball": {
+    keywords: [ "pool", "hobby", "game", "luck", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb1" src="1f3b1.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golf: {
+    keywords: [ "sports", "business", "flag", "hole", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f3" src="26f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golfing_woman: {
+    keywords: [ "sports", "business", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcc\ufe0f\u200d\u2640\ufe0f" src="1f3cc-fe0f-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golfing_man: {
+    keywords: [ "sports", "business" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcc" src="1f3cc.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  ping_pong: {
+    keywords: [ "sports", "pingpong" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd3" src="1f3d3.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  badminton: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff8" src="1f3f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  goal_net: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd45" src="1f945.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ice_hockey: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd2" src="1f3d2.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  field_hockey: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd1" src="1f3d1.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  lacrosse: {
+    keywords: [ "sports", "ball", "stick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4d" src="1f94d.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  cricket: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcf" src="1f3cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ski: {
+    keywords: [ "sports", "winter", "cold", "snow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfbf" src="1f3bf.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  skier: {
+    keywords: [ "sports", "winter", "snow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f7" src="26f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  snowboarder: {
+    keywords: [ "sports", "winter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc2" src="1f3c2.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  person_fencing: {
+    keywords: [ "sports", "fencing", "sword" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3a" src="1f93a.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  women_wrestling: {
+    keywords: [ "sports", "wrestlers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3c\u200d\u2640\ufe0f" src="1f93c-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  men_wrestling: {
+    keywords: [ "sports", "wrestlers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3c\u200d\u2642\ufe0f" src="1f93c-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  woman_cartwheeling: {
+    keywords: [ "gymnastics" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd38\u200d\u2640\ufe0f" src="1f938-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_cartwheeling: {
+    keywords: [ "gymnastics" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd38\u200d\u2642\ufe0f" src="1f938-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_playing_handball: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3e\u200d\u2640\ufe0f" src="1f93e-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_playing_handball: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3e\u200d\u2642\ufe0f" src="1f93e-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  ice_skate: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f8" src="26f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  curling_stone: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4c" src="1f94c.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  skateboard: {
+    keywords: [ "board" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef9" src="1f6f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  sled: {
+    keywords: [ "sleigh", "luge", "toboggan" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef7" src="1f6f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  bow_and_arrow: {
+    keywords: [ "sports" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff9" src="1f3f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  fishing_pole_and_fish: {
+    keywords: [ "food", "hobby", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa3" src="1f3a3.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  boxing_glove: {
+    keywords: [ "sports", "fighting" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4a" src="1f94a.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  martial_arts_uniform: {
+    keywords: [ "judo", "karate", "taekwondo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd4b" src="1f94b.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rowing_woman: {
+    keywords: [ "sports", "hobby", "water", "ship", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea3\u200d\u2640\ufe0f" src="1f6a3-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  rowing_man: {
+    keywords: [ "sports", "hobby", "water", "ship" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea3" src="1f6a3.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  climbing_woman: {
+    keywords: [ "sports", "hobby", "woman", "female", "rock" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd7\u200d\u2640\ufe0f" src="1f9d7-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  climbing_man: {
+    keywords: [ "sports", "hobby", "man", "male", "rock" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd7\u200d\u2642\ufe0f" src="1f9d7-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  swimming_woman: {
+    keywords: [ "sports", "exercise", "human", "athlete", "water", "summer", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfca\u200d\u2640\ufe0f" src="1f3ca-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  swimming_man: {
+    keywords: [ "sports", "exercise", "human", "athlete", "water", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfca" src="1f3ca.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_playing_water_polo: {
+    keywords: [ "sports", "pool" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3d\u200d\u2640\ufe0f" src="1f93d-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_playing_water_polo: {
+    keywords: [ "sports", "pool" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd3d\u200d\u2642\ufe0f" src="1f93d-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_in_lotus_position: {
+    keywords: [ "woman", "female", "meditation", "yoga", "serenity", "zen", "mindfulness" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd8\u200d\u2640\ufe0f" src="1f9d8-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_in_lotus_position: {
+    keywords: [ "man", "male", "meditation", "yoga", "serenity", "zen", "mindfulness" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddd8\u200d\u2642\ufe0f" src="1f9d8-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  surfing_woman: {
+    keywords: [ "sports", "ocean", "sea", "summer", "beach", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc4\u200d\u2640\ufe0f" src="1f3c4-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  surfing_man: {
+    keywords: [ "sports", "ocean", "sea", "summer", "beach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc4" src="1f3c4.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  bath: {
+    keywords: [ "clean", "shower", "bathroom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec0" src="1f6c0.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  basketball_woman: {
+    keywords: [ "sports", "human", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f9\ufe0f\u200d\u2640\ufe0f" src="26f9-fe0f-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  basketball_man: {
+    keywords: [ "sports", "human" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f9" src="26f9.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  weight_lifting_woman: {
+    keywords: [ "sports", "training", "exercise", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcb\ufe0f\u200d\u2640\ufe0f" src="1f3cb-fe0f-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  weight_lifting_man: {
+    keywords: [ "sports", "training", "exercise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcb" src="1f3cb.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  biking_woman: {
+    keywords: [ "sports", "bike", "exercise", "hipster", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb4\u200d\u2640\ufe0f" src="1f6b4-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  biking_man: {
+    keywords: [ "sports", "bike", "exercise", "hipster" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb4" src="1f6b4.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  mountain_biking_woman: {
+    keywords: [ "transportation", "sports", "human", "race", "bike", "woman", "female" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb5\u200d\u2640\ufe0f" src="1f6b5-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  mountain_biking_man: {
+    keywords: [ "transportation", "sports", "human", "race", "bike" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb5" src="1f6b5.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  horse_racing: {
+    keywords: [ "animal", "betting", "competition", "gambling", "luck" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc7" src="1f3c7.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  business_suit_levitating: {
+    keywords: [ "suit", "business", "levitate", "hover", "jump" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd74" src="1f574.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  trophy: {
+    keywords: [ "win", "award", "contest", "place", "ftw", "ceremony" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc6" src="1f3c6.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  running_shirt_with_sash: {
+    keywords: [ "play", "pageant" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfbd" src="1f3bd.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  medal_sports: {
+    keywords: [ "award", "winning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc5" src="1f3c5.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  medal_military: {
+    keywords: [ "award", "winning", "army" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf96" src="1f396.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "1st_place_medal": {
+    keywords: [ "award", "winning", "first" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd47" src="1f947.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "2nd_place_medal": {
+    keywords: [ "award", "second" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd48" src="1f948.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "3rd_place_medal": {
+    keywords: [ "award", "third" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd49" src="1f949.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  reminder_ribbon: {
+    keywords: [ "sports", "cause", "support", "awareness" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf97" src="1f397.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rosette: {
+    keywords: [ "flower", "decoration", "military" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff5" src="1f3f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ticket: {
+    keywords: [ "event", "concert", "pass" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfab" src="1f3ab.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  tickets: {
+    keywords: [ "sports", "concert", "entrance" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf9f" src="1f39f.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  performing_arts: {
+    keywords: [ "acting", "theater", "drama" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfad" src="1f3ad.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  art: {
+    keywords: [ "design", "paint", "draw", "colors" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa8" src="1f3a8.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  circus_tent: {
+    keywords: [ "festival", "carnival", "party" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfaa" src="1f3aa.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  woman_juggling: {
+    keywords: [ "juggle", "balance", "skill", "multitask" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd39\u200d\u2640\ufe0f" src="1f939-200d-2640-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_juggling: {
+    keywords: [ "juggle", "balance", "skill", "multitask" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd39\u200d\u2642\ufe0f" src="1f939-200d-2642-fe0f.png"/>',
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  microphone: {
+    keywords: [ "sound", "music", "PA", "sing", "talkshow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa4" src="1f3a4.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  headphones: {
+    keywords: [ "music", "score", "gadgets" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa7" src="1f3a7.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  musical_score: {
+    keywords: [ "treble", "clef", "compose" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfbc" src="1f3bc.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  musical_keyboard: {
+    keywords: [ "piano", "instrument", "compose" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb9" src="1f3b9.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  drum: {
+    keywords: [ "music", "instrument", "drumsticks", "snare" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udd41" src="1f941.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  saxophone: {
+    keywords: [ "music", "instrument", "jazz", "blues" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb7" src="1f3b7.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  trumpet: {
+    keywords: [ "music", "brass" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfba" src="1f3ba.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  guitar: {
+    keywords: [ "music", "instrument" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb8" src="1f3b8.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  violin: {
+    keywords: [ "music", "instrument", "orchestra", "symphony" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfbb" src="1f3bb.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  clapper: {
+    keywords: [ "movie", "film", "record" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfac" src="1f3ac.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  video_game: {
+    keywords: [ "play", "console", "PS4", "controller" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfae" src="1f3ae.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  space_invader: {
+    keywords: [ "game", "arcade", "play" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc7e" src="1f47e.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  dart: {
+    keywords: [ "game", "play", "bar", "target", "bullseye" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfaf" src="1f3af.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  game_die: {
+    keywords: [ "dice", "random", "tabletop", "play", "luck" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb2" src="1f3b2.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  chess_pawn: {
+    keywords: [ "expendable" ],
+    "char": "\u265f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  slot_machine: {
+    keywords: [ "bet", "gamble", "vegas", "fruit machine", "luck", "casino" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb0" src="1f3b0.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  jigsaw: {
+    keywords: [ "interlocking", "puzzle", "piece" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde9" src="1f9e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  bowling: {
+    keywords: [ "sports", "fun", "play" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb3" src="1f3b3.png"/>',
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  red_car: {
+    keywords: [ "red", "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude97" src="1f697.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  taxi: {
+    keywords: [ "uber", "vehicle", "cars", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude95" src="1f695.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  blue_car: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude99" src="1f699.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bus: {
+    keywords: [ "car", "vehicle", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8c" src="1f68c.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  trolleybus: {
+    keywords: [ "bart", "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8e" src="1f68e.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  racing_car: {
+    keywords: [ "sports", "race", "fast", "formula", "f1" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfce" src="1f3ce.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  police_car: {
+    keywords: [ "vehicle", "cars", "transportation", "law", "legal", "enforcement" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude93" src="1f693.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ambulance: {
+    keywords: [ "health", "911", "hospital" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude91" src="1f691.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fire_engine: {
+    keywords: [ "transportation", "cars", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude92" src="1f692.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  minibus: {
+    keywords: [ "vehicle", "car", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude90" src="1f690.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  truck: {
+    keywords: [ "cars", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9a" src="1f69a.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  articulated_lorry: {
+    keywords: [ "vehicle", "cars", "transportation", "express" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9b" src="1f69b.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tractor: {
+    keywords: [ "vehicle", "car", "farming", "agriculture" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9c" src="1f69c.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  kick_scooter: {
+    keywords: [ "vehicle", "kick", "razor" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef4" src="1f6f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motorcycle: {
+    keywords: [ "race", "sports", "fast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfcd" src="1f3cd.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bike: {
+    keywords: [ "sports", "bicycle", "exercise", "hipster" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb2" src="1f6b2.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motor_scooter: {
+    keywords: [ "vehicle", "vespa", "sasha" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef5" src="1f6f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rotating_light: {
+    keywords: [ "police", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea8" src="1f6a8.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_police_car: {
+    keywords: [ "vehicle", "law", "legal", "enforcement", "911" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude94" src="1f694.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_bus: {
+    keywords: [ "vehicle", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8d" src="1f68d.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_automobile: {
+    keywords: [ "car", "vehicle", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude98" src="1f698.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_taxi: {
+    keywords: [ "vehicle", "cars", "uber" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude96" src="1f696.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  aerial_tramway: {
+    keywords: [ "transportation", "vehicle", "ski" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea1" src="1f6a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_cableway: {
+    keywords: [ "transportation", "vehicle", "ski" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea0" src="1f6a0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  suspension_railway: {
+    keywords: [ "vehicle", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9f" src="1f69f.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  railway_car: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude83" src="1f683.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  train: {
+    keywords: [ "transportation", "vehicle", "carriage", "public", "travel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8b" src="1f68b.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  monorail: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9d" src="1f69d.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bullettrain_side: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude84" src="1f684.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bullettrain_front: {
+    keywords: [ "transportation", "vehicle", "speed", "fast", "public", "travel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude85" src="1f685.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  light_rail: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude88" src="1f688.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_railway: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude9e" src="1f69e.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  steam_locomotive: {
+    keywords: [ "transportation", "vehicle", "train" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude82" src="1f682.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  train2: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude86" src="1f686.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  metro: {
+    keywords: [ "transportation", "blue-square", "mrt", "underground", "tube" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude87" src="1f687.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tram: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8a" src="1f68a.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  station: {
+    keywords: [ "transportation", "vehicle", "public" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude89" src="1f689.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flying_saucer: {
+    keywords: [ "transportation", "vehicle", "ufo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef8" src="1f6f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  helicopter: {
+    keywords: [ "transportation", "vehicle", "fly" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude81" src="1f681.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  small_airplane: {
+    keywords: [ "flight", "transportation", "fly", "vehicle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee9" src="1f6e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  airplane: {
+    keywords: [ "vehicle", "transportation", "flight", "fly" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2708\ufe0f" src="2708.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flight_departure: {
+    keywords: [ "airport", "flight", "landing" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeeb" src="1f6eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flight_arrival: {
+    keywords: [ "airport", "flight", "boarding" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeec" src="1f6ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sailboat: {
+    keywords: [ "ship", "summer", "transportation", "water", "sailing" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f5" src="26f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motor_boat: {
+    keywords: [ "ship" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee5" src="1f6e5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  speedboat: {
+    keywords: [ "ship", "transportation", "vehicle", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea4" src="1f6a4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ferry: {
+    keywords: [ "boat", "ship", "yacht" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f4" src="26f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  passenger_ship: {
+    keywords: [ "yacht", "cruise", "ferry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef3" src="1f6f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rocket: {
+    keywords: [ "launch", "ship", "staffmode", "NASA", "outer space", "outer_space", "fly" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude80" src="1f680.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  artificial_satellite: {
+    keywords: [ "communication", "gps", "orbit", "spaceflight", "NASA", "ISS" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef0" src="1f6f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  seat: {
+    keywords: [ "sit", "airplane", "transport", "bus", "flight", "fly" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcba" src="1f4ba.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  canoe: {
+    keywords: [ "boat", "paddle", "water", "ship" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udef6" src="1f6f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  anchor: {
+    keywords: [ "ship", "ferry", "sea", "boat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2693" src="2693.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  construction: {
+    keywords: [ "wip", "progress", "caution", "warning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea7" src="1f6a7.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fuelpump: {
+    keywords: [ "gas station", "petroleum" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26fd" src="26fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  busstop: {
+    keywords: [ "transportation", "wait" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\ude8f" src="1f68f.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  vertical_traffic_light: {
+    keywords: [ "transportation", "driving" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea6" src="1f6a6.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  traffic_light: {
+    keywords: [ "transportation", "signal" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea5" src="1f6a5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  checkered_flag: {
+    keywords: [ "contest", "finishline", "race", "gokart" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfc1" src="1f3c1.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ship: {
+    keywords: [ "transportation", "titanic", "deploy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea2" src="1f6a2.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ferris_wheel: {
+    keywords: [ "photo", "carnival", "londoneye" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa1" src="1f3a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  roller_coaster: {
+    keywords: [ "carnival", "playground", "photo", "fun" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa2" src="1f3a2.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  carousel_horse: {
+    keywords: [ "photo", "carnival" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa0" src="1f3a0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  building_construction: {
+    keywords: [ "wip", "working", "progress" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd7" src="1f3d7.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  foggy: {
+    keywords: [ "photo", "mountain" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf01" src="1f301.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tokyo_tower: {
+    keywords: [ "photo", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddfc" src="1f5fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  factory: {
+    keywords: [ "building", "industry", "pollution", "smoke" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfed" src="1f3ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fountain: {
+    keywords: [ "photo", "summer", "water", "fresh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f2" src="26f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rice_scene: {
+    keywords: [ "photo", "japan", "asia", "tsukimi" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf91" src="1f391.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain: {
+    keywords: [ "photo", "nature", "environment" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f0" src="26f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_snow: {
+    keywords: [ "photo", "nature", "environment", "winter", "cold" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd4" src="1f3d4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mount_fuji: {
+    keywords: [ "photo", "mountain", "nature", "japanese" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddfb" src="1f5fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  volcano: {
+    keywords: [ "photo", "nature", "disaster" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0b" src="1f30b.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  japan: {
+    keywords: [ "nation", "country", "japanese", "asia" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddfe" src="1f5fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  camping: {
+    keywords: [ "photo", "outdoors", "tent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd5" src="1f3d5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tent: {
+    keywords: [ "photo", "camping", "outdoors" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26fa" src="26fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  national_park: {
+    keywords: [ "photo", "environment", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfde" src="1f3de.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motorway: {
+    keywords: [ "road", "cupertino", "interstate", "highway" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee3" src="1f6e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  railway_track: {
+    keywords: [ "train", "transportation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee4" src="1f6e4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sunrise: {
+    keywords: [ "morning", "view", "vacation", "photo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf05" src="1f305.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sunrise_over_mountains: {
+    keywords: [ "view", "vacation", "photo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf04" src="1f304.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  desert: {
+    keywords: [ "photo", "warm", "saharah" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfdc" src="1f3dc.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  beach_umbrella: {
+    keywords: [ "weather", "summer", "sunny", "sand", "mojito" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd6" src="1f3d6.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  desert_island: {
+    keywords: [ "photo", "tropical", "mojito" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfdd" src="1f3dd.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  city_sunrise: {
+    keywords: [ "photo", "good morning", "dawn" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf07" src="1f307.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  city_sunset: {
+    keywords: [ "photo", "evening", "sky", "buildings" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf06" src="1f306.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  cityscape: {
+    keywords: [ "photo", "night life", "urban" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd9" src="1f3d9.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  night_with_stars: {
+    keywords: [ "evening", "city", "downtown" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf03" src="1f303.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bridge_at_night: {
+    keywords: [ "photo", "sanfrancisco" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf09" src="1f309.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  milky_way: {
+    keywords: [ "photo", "space", "stars" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf0c" src="1f30c.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  stars: {
+    keywords: [ "night", "photo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf20" src="1f320.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sparkler: {
+    keywords: [ "stars", "night", "shine" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf87" src="1f387.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fireworks: {
+    keywords: [ "photo", "festival", "carnival", "congratulations" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf86" src="1f386.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rainbow: {
+    keywords: [ "nature", "happy", "unicorn_face", "photo", "sky", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf08" src="1f308.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  houses: {
+    keywords: [ "buildings", "photo" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfd8" src="1f3d8.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  european_castle: {
+    keywords: [ "building", "royalty", "history" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff0" src="1f3f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  japanese_castle: {
+    keywords: [ "photo", "building" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfef" src="1f3ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  stadium: {
+    keywords: [ "photo", "place", "sports", "concert", "venue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfdf" src="1f3df.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  statue_of_liberty: {
+    keywords: [ "american", "newyork" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddfd" src="1f5fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  house: {
+    keywords: [ "building", "home" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe0" src="1f3e0.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  house_with_garden: {
+    keywords: [ "home", "plant", "nature" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe1" src="1f3e1.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  derelict_house: {
+    keywords: [ "abandon", "evict", "broken", "building" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfda" src="1f3da.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  office: {
+    keywords: [ "building", "bureau", "work" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe2" src="1f3e2.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  department_store: {
+    keywords: [ "building", "shopping", "mall" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfec" src="1f3ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  post_office: {
+    keywords: [ "building", "envelope", "communication" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe3" src="1f3e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  european_post_office: {
+    keywords: [ "building", "email" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe4" src="1f3e4.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  hospital: {
+    keywords: [ "building", "health", "surgery", "doctor" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe5" src="1f3e5.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bank: {
+    keywords: [ "building", "money", "sales", "cash", "business", "enterprise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe6" src="1f3e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  hotel: {
+    keywords: [ "building", "accomodation", "checkin" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe8" src="1f3e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  convenience_store: {
+    keywords: [ "building", "shopping", "groceries" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfea" src="1f3ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  school: {
+    keywords: [ "building", "student", "education", "learn", "teach" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfeb" src="1f3eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  love_hotel: {
+    keywords: [ "like", "affection", "dating" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe9" src="1f3e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  wedding: {
+    keywords: [ "love", "like", "affection", "couple", "marriage", "bride", "groom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc92" src="1f492.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  classical_building: {
+    keywords: [ "art", "culture", "history" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfdb" src="1f3db.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  church: {
+    keywords: [ "building", "religion", "christ" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ea" src="26ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mosque: {
+    keywords: [ "islam", "worship", "minaret" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd4c" src="1f54c.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  synagogue: {
+    keywords: [ "judaism", "worship", "temple", "jewish" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd4d" src="1f54d.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  kaaba: {
+    keywords: [ "mecca", "mosque", "islam" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd4b" src="1f54b.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  shinto_shrine: {
+    keywords: [ "temple", "japan", "kyoto" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26e9" src="26e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  watch: {
+    keywords: [ "time", "accessories" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u231a" src="231a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  iphone: {
+    keywords: [ "technology", "apple", "gadgets", "dial" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf1" src="1f4f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  calling: {
+    keywords: [ "iphone", "incoming" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf2" src="1f4f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  computer: {
+    keywords: [ "technology", "laptop", "screen", "display", "monitor" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcbb" src="1f4bb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  keyboard: {
+    keywords: [ "technology", "computer", "type", "input", "text" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2328" src="2328.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  desktop_computer: {
+    keywords: [ "technology", "computing", "screen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udda5" src="1f5a5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  printer: {
+    keywords: [ "paper", "ink" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udda8" src="1f5a8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  computer_mouse: {
+    keywords: [ "click" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddb1" src="1f5b1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  trackball: {
+    keywords: [ "technology", "trackpad" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddb2" src="1f5b2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  joystick: {
+    keywords: [ "game", "play" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd79" src="1f579.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  clamp: {
+    keywords: [ "tool" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udddc" src="1f5dc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  minidisc: {
+    keywords: [ "technology", "record", "data", "disk", "90s" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcbd" src="1f4bd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  floppy_disk: {
+    keywords: [ "oldschool", "technology", "save", "90s", "80s" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcbe" src="1f4be.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  cd: {
+    keywords: [ "technology", "dvd", "disk", "disc", "90s" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcbf" src="1f4bf.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dvd: {
+    keywords: [ "cd", "disk", "disc" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc0" src="1f4c0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  vhs: {
+    keywords: [ "record", "video", "oldschool", "90s", "80s" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcfc" src="1f4fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  camera: {
+    keywords: [ "gadgets", "photography" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf7" src="1f4f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  camera_flash: {
+    keywords: [ "photography", "gadgets" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf8" src="1f4f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  video_camera: {
+    keywords: [ "film", "record" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf9" src="1f4f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  movie_camera: {
+    keywords: [ "film", "record" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa5" src="1f3a5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  film_projector: {
+    keywords: [ "video", "tape", "record", "movie" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcfd" src="1f4fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  film_strip: {
+    keywords: [ "movie" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf9e" src="1f39e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  telephone_receiver: {
+    keywords: [ "technology", "communication", "dial" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcde" src="1f4de.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  phone: {
+    keywords: [ "technology", "communication", "dial", "telephone" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u260e\ufe0f" src="260e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pager: {
+    keywords: [ "bbcall", "oldschool", "90s" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcdf" src="1f4df.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fax: {
+    keywords: [ "communication", "technology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce0" src="1f4e0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  tv: {
+    keywords: [ "technology", "program", "oldschool", "show", "television" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcfa" src="1f4fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  radio: {
+    keywords: [ "communication", "music", "podcast", "program" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcfb" src="1f4fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  studio_microphone: {
+    keywords: [ "sing", "recording", "artist", "talkshow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf99" src="1f399.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  level_slider: {
+    keywords: [ "scale" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf9a" src="1f39a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  control_knobs: {
+    keywords: [ "dial" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf9b" src="1f39b.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  compass: {
+    keywords: [ "magnetic", "navigation", "orienteering" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udded" src="1f9ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  stopwatch: {
+    keywords: [ "time", "deadline" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f1" src="23f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  timer_clock: {
+    keywords: [ "alarm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f2" src="23f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  alarm_clock: {
+    keywords: [ "time", "wake" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f0" src="23f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mantelpiece_clock: {
+    keywords: [ "time" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd70" src="1f570.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hourglass_flowing_sand: {
+    keywords: [ "oldschool", "time", "countdown" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f3" src="23f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hourglass: {
+    keywords: [ "time", "clock", "oldschool", "limit", "exam", "quiz", "test" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u231b" src="231b.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  satellite: {
+    keywords: [ "communication", "future", "radio", "space" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce1" src="1f4e1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  battery: {
+    keywords: [ "power", "energy", "sustain" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0b" src="1f50b.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  electric_plug: {
+    keywords: [ "charger", "power" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0c" src="1f50c.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bulb: {
+    keywords: [ "light", "electricity", "idea" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca1" src="1f4a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  flashlight: {
+    keywords: [ "dark", "camping", "sight", "night" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd26" src="1f526.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  candle: {
+    keywords: [ "fire", "wax" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd6f" src="1f56f.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fire_extinguisher: {
+    keywords: [ "quench" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddef" src="1f9ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wastebasket: {
+    keywords: [ "bin", "trash", "rubbish", "garbage", "toss" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddd1" src="1f5d1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  oil_drum: {
+    keywords: [ "barrell" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee2" src="1f6e2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  money_with_wings: {
+    keywords: [ "dollar", "bills", "payment", "sale" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb8" src="1f4b8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dollar: {
+    keywords: [ "money", "sales", "bill", "currency" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb5" src="1f4b5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  yen: {
+    keywords: [ "money", "sales", "japanese", "dollar", "currency" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb4" src="1f4b4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  euro: {
+    keywords: [ "money", "sales", "dollar", "currency" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb6" src="1f4b6.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pound: {
+    keywords: [ "british", "sterling", "money", "sales", "bills", "uk", "england", "currency" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb7" src="1f4b7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  moneybag: {
+    keywords: [ "dollar", "payment", "coins", "sale" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb0" src="1f4b0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  credit_card: {
+    keywords: [ "money", "sales", "dollar", "bill", "payment", "shopping" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb3" src="1f4b3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gem: {
+    keywords: [ "blue", "ruby", "diamond", "jewelry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8e" src="1f48e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  balance_scale: {
+    keywords: [ "law", "fairness", "weight" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2696" src="2696.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toolbox: {
+    keywords: [ "tools", "diy", "fix", "maintainer", "mechanic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf0" src="1f9f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wrench: {
+    keywords: [ "tools", "diy", "ikea", "fix", "maintainer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd27" src="1f527.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer: {
+    keywords: [ "tools", "build", "create" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd28" src="1f528.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer_and_pick: {
+    keywords: [ "tools", "build", "create" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2692" src="2692.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer_and_wrench: {
+    keywords: [ "tools", "build", "create" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee0" src="1f6e0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pick: {
+    keywords: [ "tools", "dig" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26cf" src="26cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  nut_and_bolt: {
+    keywords: [ "handy", "tools", "fix" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd29" src="1f529.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gear: {
+    keywords: [ "cog" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2699" src="2699.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  brick: {
+    keywords: [ "bricks" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf1" src="1f9f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chains: {
+    keywords: [ "lock", "arrest" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d3" src="26d3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  magnet: {
+    keywords: [ "attraction", "magnetic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf2" src="1f9f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gun: {
+    keywords: [ "violence", "weapon", "pistol", "revolver" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2b" src="1f52b.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bomb: {
+    keywords: [ "boom", "explode", "explosion", "terrorism" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca3" src="1f4a3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  firecracker: {
+    keywords: [ "dynamite", "boom", "explode", "explosion", "explosive" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde8" src="1f9e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hocho: {
+    keywords: [ "knife", "blade", "cutlery", "kitchen", "weapon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2a" src="1f52a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dagger: {
+    keywords: [ "weapon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udde1" src="1f5e1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crossed_swords: {
+    keywords: [ "weapon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2694" src="2694.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shield: {
+    keywords: [ "protection", "security" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udee1" src="1f6e1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  smoking: {
+    keywords: [ "kills", "tobacco", "cigarette", "joint", "smoke" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeac" src="1f6ac.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  skull_and_crossbones: {
+    keywords: [ "poison", "danger", "deadly", "scary", "death", "pirate", "evil" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2620" src="2620.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  coffin: {
+    keywords: [ "vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26b0" src="26b0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  funeral_urn: {
+    keywords: [ "dead", "die", "death", "rip", "ashes" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26b1" src="26b1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  amphora: {
+    keywords: [ "vase", "jar" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udffa" src="1f3fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crystal_ball: {
+    keywords: [ "disco", "party", "magic", "circus", "fortune_teller" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2e" src="1f52e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  prayer_beads: {
+    keywords: [ "dhikr", "religious" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcff" src="1f4ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  nazar_amulet: {
+    keywords: [ "bead", "charm" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddff" src="1f9ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  barber: {
+    keywords: [ "hair", "salon", "style" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc88" src="1f488.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  alembic: {
+    keywords: [ "distilling", "science", "experiment", "chemistry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2697" src="2697.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  telescope: {
+    keywords: [ "stars", "space", "zoom", "science", "astronomy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2d" src="1f52d.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  microscope: {
+    keywords: [ "laboratory", "experiment", "zoomin", "science", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2c" src="1f52c.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hole: {
+    keywords: [ "embarrassing" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd73" src="1f573.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pill: {
+    keywords: [ "health", "medicine", "doctor", "pharmacy", "drug" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8a" src="1f48a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  syringe: {
+    keywords: [ "health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc89" src="1f489.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dna: {
+    keywords: [ "biologist", "genetics", "life" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddec" src="1f9ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  microbe: {
+    keywords: [ "amoeba", "bacteria", "germs" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udda0" src="1f9a0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  petri_dish: {
+    keywords: [ "bacteria", "biology", "culture", "lab" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddeb" src="1f9eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  test_tube: {
+    keywords: [ "chemistry", "experiment", "lab", "science" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddea" src="1f9ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  thermometer: {
+    keywords: [ "weather", "temperature", "hot", "cold" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf21" src="1f321.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  broom: {
+    keywords: [ "cleaning", "sweeping", "witch" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf9" src="1f9f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  basket: {
+    keywords: [ "laundry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddfa" src="1f9fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toilet_paper: {
+    keywords: [ "roll" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddfb" src="1f9fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  label: {
+    keywords: [ "sale", "tag" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff7" src="1f3f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bookmark: {
+    keywords: [ "favorite", "label", "save" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd16" src="1f516.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toilet: {
+    keywords: [ "restroom", "wc", "washroom", "bathroom", "potty" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udebd" src="1f6bd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shower: {
+    keywords: [ "clean", "water", "bathroom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udebf" src="1f6bf.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bathtub: {
+    keywords: [ "clean", "shower", "bathroom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec1" src="1f6c1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  soap: {
+    keywords: [ "bar", "bathing", "cleaning", "lather" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddfc" src="1f9fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  sponge: {
+    keywords: [ "absorbing", "cleaning", "porous" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddfd" src="1f9fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lotion_bottle: {
+    keywords: [ "moisturizer", "sunscreen" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf4" src="1f9f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  key: {
+    keywords: [ "lock", "door", "password" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd11" src="1f511.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  old_key: {
+    keywords: [ "lock", "door", "password" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udddd" src="1f5dd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  couch_and_lamp: {
+    keywords: [ "read", "chill" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udecb" src="1f6cb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  sleeping_bed: {
+    keywords: [ "bed", "rest" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udecc" src="1f6cc.png"/>',
+    fitzpatrick_scale: true,
+    category: "objects"
+  },
+  bed: {
+    keywords: [ "sleep", "rest" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udecf" src="1f6cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  door: {
+    keywords: [ "house", "entry", "exit" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeaa" src="1f6aa.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bellhop_bell: {
+    keywords: [ "service" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udece" src="1f6ce.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  teddy_bear: {
+    keywords: [ "plush", "stuffed" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf8" src="1f9f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  framed_picture: {
+    keywords: [ "photography" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddbc" src="1f5bc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  world_map: {
+    keywords: [ "location", "direction" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddfa" src="1f5fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  parasol_on_ground: {
+    keywords: [ "weather", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f1" src="26f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  moyai: {
+    keywords: [ "rock", "easter island", "moai" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddff" src="1f5ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shopping: {
+    keywords: [ "mall", "buy", "purchase" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udecd" src="1f6cd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shopping_cart: {
+    keywords: [ "trolley" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uded2" src="1f6d2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  balloon: {
+    keywords: [ "party", "celebration", "birthday", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf88" src="1f388.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  flags: {
+    keywords: [ "fish", "japanese", "koinobori", "carp", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8f" src="1f38f.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ribbon: {
+    keywords: [ "decoration", "pink", "girl", "bowtie" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf80" src="1f380.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gift: {
+    keywords: [ "present", "birthday", "christmas", "xmas" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf81" src="1f381.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  confetti_ball: {
+    keywords: [ "festival", "party", "birthday", "circus" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8a" src="1f38a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  tada: {
+    keywords: [ "party", "congratulations", "birthday", "magic", "circus", "celebration" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf89" src="1f389.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dolls: {
+    keywords: [ "japanese", "toy", "kimono" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8e" src="1f38e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wind_chime: {
+    keywords: [ "nature", "ding", "spring", "bell" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf90" src="1f390.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crossed_flags: {
+    keywords: [ "japanese", "nation", "country", "border" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf8c" src="1f38c.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  izakaya_lantern: {
+    keywords: [ "light", "paper", "halloween", "spooky" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfee" src="1f3ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  red_envelope: {
+    keywords: [ "gift" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde7" src="1f9e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  email: {
+    keywords: [ "letter", "postal", "inbox", "communication" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2709\ufe0f" src="2709.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  envelope_with_arrow: {
+    keywords: [ "email", "communication" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce9" src="1f4e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  incoming_envelope: {
+    keywords: [ "email", "inbox" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce8" src="1f4e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  "e-mail": {
+    keywords: [ "communication", "inbox" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce7" src="1f4e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  love_letter: {
+    keywords: [ "email", "like", "affection", "envelope", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc8c" src="1f48c.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  postbox: {
+    keywords: [ "email", "letter", "envelope" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcee" src="1f4ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_closed: {
+    keywords: [ "email", "communication", "inbox" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcea" src="1f4ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox: {
+    keywords: [ "email", "inbox", "communication" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udceb" src="1f4eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_with_mail: {
+    keywords: [ "email", "inbox", "communication" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcec" src="1f4ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_with_no_mail: {
+    keywords: [ "email", "inbox" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udced" src="1f4ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  "package": {
+    keywords: [ "mail", "gift", "cardboard", "box", "moving" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce6" src="1f4e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  postal_horn: {
+    keywords: [ "instrument", "music" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcef" src="1f4ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  inbox_tray: {
+    keywords: [ "email", "documents" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce5" src="1f4e5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  outbox_tray: {
+    keywords: [ "inbox", "email" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce4" src="1f4e4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  scroll: {
+    keywords: [ "documents", "ancient", "history", "paper" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcdc" src="1f4dc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  page_with_curl: {
+    keywords: [ "documents", "office", "paper" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc3" src="1f4c3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bookmark_tabs: {
+    keywords: [ "favorite", "save", "order", "tidy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd1" src="1f4d1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  receipt: {
+    keywords: [ "accounting", "expenses" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddfe" src="1f9fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bar_chart: {
+    keywords: [ "graph", "presentation", "stats" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcca" src="1f4ca.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chart_with_upwards_trend: {
+    keywords: [ "graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc8" src="1f4c8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chart_with_downwards_trend: {
+    keywords: [ "graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc9" src="1f4c9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  page_facing_up: {
+    keywords: [ "documents", "office", "paper", "information" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc4" src="1f4c4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  date: {
+    keywords: [ "calendar", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc5" src="1f4c5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  calendar: {
+    keywords: [ "schedule", "date", "planning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc6" src="1f4c6.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  spiral_calendar: {
+    keywords: [ "date", "schedule", "planning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddd3" src="1f5d3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_index: {
+    keywords: [ "business", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc7" src="1f4c7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_file_box: {
+    keywords: [ "business", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddc3" src="1f5c3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ballot_box: {
+    keywords: [ "election", "vote" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddf3" src="1f5f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  file_cabinet: {
+    keywords: [ "filing", "organizing" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddc4" src="1f5c4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  clipboard: {
+    keywords: [ "stationery", "documents" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udccb" src="1f4cb.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  spiral_notepad: {
+    keywords: [ "memo", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddd2" src="1f5d2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  file_folder: {
+    keywords: [ "documents", "business", "office" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc1" src="1f4c1.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  open_file_folder: {
+    keywords: [ "documents", "load" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcc2" src="1f4c2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_index_dividers: {
+    keywords: [ "organizing", "business", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddc2" src="1f5c2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  newspaper_roll: {
+    keywords: [ "press", "headline" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddde" src="1f5de.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  newspaper: {
+    keywords: [ "press", "headline" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf0" src="1f4f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  notebook: {
+    keywords: [ "stationery", "record", "notes", "paper", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd3" src="1f4d3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  closed_book: {
+    keywords: [ "read", "library", "knowledge", "textbook", "learn" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd5" src="1f4d5.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  green_book: {
+    keywords: [ "read", "library", "knowledge", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd7" src="1f4d7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  blue_book: {
+    keywords: [ "read", "library", "knowledge", "learn", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd8" src="1f4d8.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  orange_book: {
+    keywords: [ "read", "library", "knowledge", "textbook", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd9" src="1f4d9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  notebook_with_decorative_cover: {
+    keywords: [ "classroom", "notes", "record", "paper", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd4" src="1f4d4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ledger: {
+    keywords: [ "notes", "paper" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd2" src="1f4d2.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  books: {
+    keywords: [ "literature", "library", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcda" src="1f4da.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  open_book: {
+    keywords: [ "book", "read", "library", "knowledge", "literature", "learn", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd6" src="1f4d6.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  safety_pin: {
+    keywords: [ "diaper" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddf7" src="1f9f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  link: {
+    keywords: [ "rings", "url" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd17" src="1f517.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paperclip: {
+    keywords: [ "documents", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcce" src="1f4ce.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paperclips: {
+    keywords: [ "documents", "stationery" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd87" src="1f587.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  scissors: {
+    keywords: [ "stationery", "cut" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2702\ufe0f" src="2702.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  triangular_ruler: {
+    keywords: [ "stationery", "math", "architect", "sketch" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcd0" src="1f4d0.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  straight_ruler: {
+    keywords: [ "stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udccf" src="1f4cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  abacus: {
+    keywords: [ "calculation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\uddee" src="1f9ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pushpin: {
+    keywords: [ "stationery", "mark", "here" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udccc" src="1f4cc.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  round_pushpin: {
+    keywords: [ "stationery", "location", "map", "here" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udccd" src="1f4cd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  triangular_flag_on_post: {
+    keywords: [ "mark", "milestone", "place" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udea9" src="1f6a9.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  white_flag: {
+    keywords: [ "losing", "loser", "lost", "surrender", "give up", "fail" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff3" src="1f3f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  black_flag: {
+    keywords: [ "pirate" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff4" src="1f3f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  rainbow_flag: {
+    keywords: [ "flag", "rainbow", "pride", "gay", "lgbt", "glbt", "queer", "homosexual", "lesbian", "bisexual", "transgender" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff3\ufe0f\u200d\ud83c\udf08" src="1f3f3-fe0f-200d-1f308.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  closed_lock_with_key: {
+    keywords: [ "security", "privacy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd10" src="1f510.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lock: {
+    keywords: [ "security", "password", "padlock" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd12" src="1f512.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  unlock: {
+    keywords: [ "privacy", "security" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd13" src="1f513.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lock_with_ink_pen: {
+    keywords: [ "security", "secret" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0f" src="1f50f.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pen: {
+    keywords: [ "stationery", "writing", "write" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd8a" src="1f58a.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fountain_pen: {
+    keywords: [ "stationery", "writing", "write" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd8b" src="1f58b.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  black_nib: {
+    keywords: [ "pen", "stationery", "writing", "write" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2712\ufe0f" src="2712.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  memo: {
+    keywords: [ "write", "documents", "stationery", "pencil", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcdd" src="1f4dd.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pencil2: {
+    keywords: [ "stationery", "write", "paper", "writing", "school", "study" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270f\ufe0f" src="270f.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crayon: {
+    keywords: [ "drawing", "creativity" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd8d" src="1f58d.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paintbrush: {
+    keywords: [ "drawing", "creativity", "art" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd8c" src="1f58c.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mag: {
+    keywords: [ "search", "zoom", "find", "detective" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0d" src="1f50d.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mag_right: {
+    keywords: [ "search", "zoom", "find", "detective" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0e" src="1f50e.png"/>',
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  heart: {
+    keywords: [ "love", "like", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2764\ufe0f" src="2764.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  orange_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83e\udde1" src="1f9e1.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  yellow_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9b" src="1f49b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  green_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9a" src="1f49a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  blue_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc99" src="1f499.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  purple_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9c" src="1f49c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_heart: {
+    keywords: [ "evil" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udda4" src="1f5a4.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  broken_heart: {
+    keywords: [ "sad", "sorry", "break", "heart", "heartbreak" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc94" src="1f494.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_heart_exclamation: {
+    keywords: [ "decoration", "love" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2763" src="2763.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  two_hearts: {
+    keywords: [ "love", "like", "affection", "valentines", "heart" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc95" src="1f495.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  revolving_hearts: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9e" src="1f49e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heartbeat: {
+    keywords: [ "love", "like", "affection", "valentines", "pink", "heart" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc93" src="1f493.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heartpulse: {
+    keywords: [ "like", "love", "affection", "valentines", "pink" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc97" src="1f497.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sparkling_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc96" src="1f496.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cupid: {
+    keywords: [ "love", "like", "heart", "affection", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc98" src="1f498.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  gift_heart: {
+    keywords: [ "love", "valentines" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9d" src="1f49d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heart_decoration: {
+    keywords: [ "purple-square", "love", "like" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udc9f" src="1f49f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  peace_symbol: {
+    keywords: [ "hippie" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262e" src="262e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  latin_cross: {
+    keywords: [ "christianity" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u271d" src="271d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  star_and_crescent: {
+    keywords: [ "islam" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262a" src="262a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  om: {
+    keywords: [ "hinduism", "buddhism", "sikhism", "jainism" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd49" src="1f549.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wheel_of_dharma: {
+    keywords: [ "hinduism", "buddhism", "sikhism", "jainism" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2638" src="2638.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  star_of_david: {
+    keywords: [ "judaism" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2721" src="2721.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  six_pointed_star: {
+    keywords: [ "purple-square", "religion", "jewish", "hexagram" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd2f" src="1f52f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  menorah: {
+    keywords: [ "hanukkah", "candles", "jewish" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd4e" src="1f54e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  yin_yang: {
+    keywords: [ "balance" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262f" src="262f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  orthodox_cross: {
+    keywords: [ "suppedaneum", "religion" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2626" src="2626.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  place_of_worship: {
+    keywords: [ "religion", "church", "temple", "prayer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uded0" src="1f6d0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ophiuchus: {
+    keywords: [ "sign", "purple-square", "constellation", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ce" src="26ce.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  aries: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2648" src="2648.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  taurus: {
+    keywords: [ "purple-square", "sign", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2649" src="2649.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  gemini: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264a" src="264a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cancer: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264b" src="264b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  leo: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264c" src="264c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  virgo: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264d" src="264d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  libra: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264e" src="264e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  scorpius: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology", "scorpio" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264f" src="264f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sagittarius: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2650" src="2650.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  capricorn: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2651" src="2651.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  aquarius: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2652" src="2652.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  pisces: {
+    keywords: [ "purple-square", "sign", "zodiac", "astrology" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2653" src="2653.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  id: {
+    keywords: [ "purple-square", "words" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd94" src="1f194.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  atom_symbol: {
+    keywords: [ "science", "physics", "chemistry" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u269b" src="269b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7a7a: {
+    keywords: [ "kanji", "japanese", "chinese", "empty", "sky", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude33" src="1f233.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u5272: {
+    keywords: [ "cut", "divide", "chinese", "kanji", "pink-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude39" src="1f239.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  radioactive: {
+    keywords: [ "nuclear", "danger" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2622" src="2622.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  biohazard: {
+    keywords: [ "danger" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2623" src="2623.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mobile_phone_off: {
+    keywords: [ "mute", "orange-square", "silence", "quiet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf4" src="1f4f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  vibration_mode: {
+    keywords: [ "orange-square", "phone" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf3" src="1f4f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6709: {
+    keywords: [ "orange-square", "chinese", "have", "kanji" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude36" src="1f236.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7121: {
+    keywords: [ "nothing", "chinese", "kanji", "japanese", "orange-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude1a" src="1f21a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7533: {
+    keywords: [ "chinese", "japanese", "kanji", "orange-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude38" src="1f238.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u55b6: {
+    keywords: [ "japanese", "opening hours", "orange-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude3a" src="1f23a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6708: {
+    keywords: [ "chinese", "month", "moon", "japanese", "orange-square", "kanji" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude37\ufe0f" src="1f237.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight_pointed_black_star: {
+    keywords: [ "orange-square", "shape", "polygon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2734\ufe0f" src="2734.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  vs: {
+    keywords: [ "words", "orange-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd9a" src="1f19a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  accept: {
+    keywords: [ "ok", "good", "chinese", "kanji", "agree", "yes", "orange-circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude51" src="1f251.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_flower: {
+    keywords: [ "japanese", "spring" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcae" src="1f4ae.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ideograph_advantage: {
+    keywords: [ "chinese", "kanji", "obtain", "get", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude50" src="1f250.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  secret: {
+    keywords: [ "privacy", "chinese", "sshh", "kanji", "red-circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3299\ufe0f" src="3299.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  congratulations: {
+    keywords: [ "chinese", "kanji", "japanese", "red-circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3297\ufe0f" src="3297.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u5408: {
+    keywords: [ "japanese", "chinese", "join", "kanji", "red-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude34" src="1f234.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6e80: {
+    keywords: [ "full", "chinese", "japanese", "red-square", "kanji" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude35" src="1f235.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7981: {
+    keywords: [ "kanji", "japanese", "chinese", "forbidden", "limit", "restricted", "red-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude32" src="1f232.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  a: {
+    keywords: [ "red-square", "alphabet", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd70\ufe0f" src="1f170.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  b: {
+    keywords: [ "red-square", "alphabet", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd71\ufe0f" src="1f171.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ab: {
+    keywords: [ "red-square", "alphabet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd8e" src="1f18e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cl: {
+    keywords: [ "alphabet", "words", "red-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd91" src="1f191.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  o2: {
+    keywords: [ "alphabet", "red-square", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd7e\ufe0f" src="1f17e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sos: {
+    keywords: [ "help", "red-square", "words", "emergency", "911" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd98" src="1f198.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_entry: {
+    keywords: [ "limit", "security", "privacy", "bad", "denied", "stop", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d4" src="26d4.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  name_badge: {
+    keywords: [ "fire", "forbid" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcdb" src="1f4db.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_entry_sign: {
+    keywords: [ "forbid", "stop", "limit", "denied", "disallow", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeab" src="1f6ab.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  x: {
+    keywords: [ "no", "delete", "remove", "cancel", "red" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u274c" src="274c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  o: {
+    keywords: [ "circle", "round" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b55" src="2b55.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  stop_sign: {
+    keywords: [ "stop" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uded1" src="1f6d1.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  anger: {
+    keywords: [ "angry", "mad" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca2" src="1f4a2.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hotsprings: {
+    keywords: [ "bath", "warm", "relax" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2668\ufe0f" src="2668.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_pedestrians: {
+    keywords: [ "rules", "crossing", "walking", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb7" src="1f6b7.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  do_not_litter: {
+    keywords: [ "trash", "bin", "garbage", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeaf" src="1f6af.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_bicycles: {
+    keywords: [ "cyclist", "prohibited", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb3" src="1f6b3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  "non-potable_water": {
+    keywords: [ "drink", "faucet", "tap", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb1" src="1f6b1.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  underage: {
+    keywords: [ "18", "drink", "pub", "night", "minor", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1e" src="1f51e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_mobile_phones: {
+    keywords: [ "iphone", "mute", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf5" src="1f4f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  exclamation: {
+    keywords: [ "heavy_exclamation_mark", "danger", "surprise", "punctuation", "wow", "warning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2757" src="2757.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  grey_exclamation: {
+    keywords: [ "surprise", "punctuation", "gray", "wow", "warning" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2755" src="2755.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  question: {
+    keywords: [ "doubt", "confused" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2753" src="2753.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  grey_question: {
+    keywords: [ "doubts", "gray", "huh", "confused" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2754" src="2754.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  bangbang: {
+    keywords: [ "exclamation", "surprise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u203c\ufe0f" src="203c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  interrobang: {
+    keywords: [ "wat", "punctuation", "surprise" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2049\ufe0f" src="2049.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  low_brightness: {
+    keywords: [ "sun", "afternoon", "warm", "summer" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd05" src="1f505.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  high_brightness: {
+    keywords: [ "sun", "light" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd06" src="1f506.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  trident: {
+    keywords: [ "weapon", "spear" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd31" src="1f531.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  fleur_de_lis: {
+    keywords: [ "decorative", "scout" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u269c" src="269c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  part_alternation_mark: {
+    keywords: [ "graph", "presentation", "stats", "business", "economics", "bad" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u303d\ufe0f" src="303d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  warning: {
+    keywords: [ "exclamation", "wip", "alert", "error", "problem", "issue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26a0\ufe0f" src="26a0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  children_crossing: {
+    keywords: [ "school", "warning", "danger", "sign", "driving", "yellow-diamond" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb8" src="1f6b8.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  beginner: {
+    keywords: [ "badge", "shield" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd30" src="1f530.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  recycle: {
+    keywords: [ "arrow", "environment", "garbage", "trash" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267b\ufe0f" src="267b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6307: {
+    keywords: [ "chinese", "point", "green-square", "kanji" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude2f" src="1f22f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  chart: {
+    keywords: [ "green-square", "graph", "presentation", "stats" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb9" src="1f4b9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sparkle: {
+    keywords: [ "stars", "green-square", "awesome", "good", "fireworks" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2747\ufe0f" src="2747.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight_spoked_asterisk: {
+    keywords: [ "star", "sparkle", "green-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2733\ufe0f" src="2733.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  negative_squared_cross_mark: {
+    keywords: [ "x", "green-square", "no", "deny" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u274e" src="274e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_check_mark: {
+    keywords: [ "green-square", "ok", "agree", "vote", "election", "answer", "tick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2705" src="2705.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  diamond_shape_with_a_dot_inside: {
+    keywords: [ "jewel", "blue", "gem", "crystal", "fancy" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udca0" src="1f4a0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cyclone: {
+    keywords: [ "weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf00" src="1f300.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loop: {
+    keywords: [ "tape", "cassette" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27bf" src="27bf.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  globe_with_meridians: {
+    keywords: [ "earth", "international", "world", "internet", "interweb", "i18n" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udf10" src="1f310.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  m: {
+    keywords: [ "alphabet", "blue-circle", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u24c2\ufe0f" src="24c2.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  atm: {
+    keywords: [ "money", "sales", "cash", "blue-square", "payment", "bank" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfe7" src="1f3e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sa: {
+    keywords: [ "japanese", "blue-square", "katakana" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude02\ufe0f" src="1f202.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  passport_control: {
+    keywords: [ "custom", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec2" src="1f6c2.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  customs: {
+    keywords: [ "passport", "border", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec3" src="1f6c3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  baggage_claim: {
+    keywords: [ "blue-square", "airport", "transport" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec4" src="1f6c4.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_luggage: {
+    keywords: [ "blue-square", "travel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udec5" src="1f6c5.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wheelchair: {
+    keywords: [ "blue-square", "disabled", "a11y", "accessibility" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267f" src="267f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_smoking: {
+    keywords: [ "cigarette", "blue-square", "smell", "smoke" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udead" src="1f6ad.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wc: {
+    keywords: [ "toilet", "restroom", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udebe" src="1f6be.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  parking: {
+    keywords: [ "cars", "blue-square", "alphabet", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd7f\ufe0f" src="1f17f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  potable_water: {
+    keywords: [ "blue-square", "liquid", "restroom", "cleaning", "faucet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb0" src="1f6b0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mens: {
+    keywords: [ "toilet", "restroom", "wc", "blue-square", "gender", "male" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeb9" src="1f6b9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  womens: {
+    keywords: [ "purple-square", "woman", "female", "toilet", "loo", "restroom", "gender" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeba" src="1f6ba.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  baby_symbol: {
+    keywords: [ "orange-square", "child" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udebc" src="1f6bc.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  restroom: {
+    keywords: [ "blue-square", "toilet", "refresh", "wc", "gender" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udebb" src="1f6bb.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  put_litter_in_its_place: {
+    keywords: [ "blue-square", "sign", "human", "info" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udeae" src="1f6ae.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cinema: {
+    keywords: [ "blue-square", "record", "film", "movie", "curtain", "stage", "theater" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfa6" src="1f3a6.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  signal_strength: {
+    keywords: [ "blue-square", "reception", "phone", "internet", "connection", "wifi", "bluetooth", "bars" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcf6" src="1f4f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  koko: {
+    keywords: [ "blue-square", "here", "katakana", "japanese", "destination" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\ude01" src="1f201.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ng: {
+    keywords: [ "blue-square", "words", "shape", "icon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd96" src="1f196.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ok: {
+    keywords: [ "good", "agree", "yes", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd97" src="1f197.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  up: {
+    keywords: [ "blue-square", "above", "high" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd99" src="1f199.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cool: {
+    keywords: [ "words", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd92" src="1f192.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  "new": {
+    keywords: [ "blue-square", "words", "start" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd95" src="1f195.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  free: {
+    keywords: [ "blue-square", "words" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udd93" src="1f193.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  zero: {
+    keywords: [ "0", "numbers", "blue-square", "null" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="0\ufe0f\u20e3" src="30-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  one: {
+    keywords: [ "blue-square", "numbers", "1" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="1\ufe0f\u20e3" src="31-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  two: {
+    keywords: [ "numbers", "2", "prime", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="2\ufe0f\u20e3" src="32-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  three: {
+    keywords: [ "3", "numbers", "prime", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="3\ufe0f\u20e3" src="33-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  four: {
+    keywords: [ "4", "numbers", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="4\ufe0f\u20e3" src="34-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  five: {
+    keywords: [ "5", "numbers", "blue-square", "prime" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="5\ufe0f\u20e3" src="35-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  six: {
+    keywords: [ "6", "numbers", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="6\ufe0f\u20e3" src="36-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  seven: {
+    keywords: [ "7", "numbers", "blue-square", "prime" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="7\ufe0f\u20e3" src="37-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight: {
+    keywords: [ "8", "blue-square", "numbers" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="8\ufe0f\u20e3" src="38-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  nine: {
+    keywords: [ "blue-square", "numbers", "9" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="9\ufe0f\u20e3" src="39-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  keycap_ten: {
+    keywords: [ "numbers", "10", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1f" src="1f51f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  asterisk: {
+    keywords: [ "star", "keycap" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="*\u20e3" src="2a-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eject_button: {
+    keywords: [ "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23cf\ufe0f" src="23cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_forward: {
+    keywords: [ "blue-square", "right", "direction", "play" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25b6\ufe0f" src="25b6.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  pause_button: {
+    keywords: [ "pause", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f8" src="23f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  next_track_button: {
+    keywords: [ "forward", "next", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ed" src="23ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  stop_button: {
+    keywords: [ "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f9" src="23f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  record_button: {
+    keywords: [ "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23fa" src="23fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  play_or_pause_button: {
+    keywords: [ "blue-square", "play", "pause" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ef" src="23ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  previous_track_button: {
+    keywords: [ "backward" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ee" src="23ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  fast_forward: {
+    keywords: [ "blue-square", "play", "speed", "continue" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23e9" src="23e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  rewind: {
+    keywords: [ "play", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ea" src="23ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  twisted_rightwards_arrows: {
+    keywords: [ "blue-square", "shuffle", "music", "random" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd00" src="1f500.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  repeat: {
+    keywords: [ "loop", "record" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd01" src="1f501.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  repeat_one: {
+    keywords: [ "blue-square", "loop" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd02" src="1f502.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_backward: {
+    keywords: [ "blue-square", "left", "direction" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25c0\ufe0f" src="25c0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up_small: {
+    keywords: [ "blue-square", "triangle", "direction", "point", "forward", "top" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd3c" src="1f53c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_down_small: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd3d" src="1f53d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_double_up: {
+    keywords: [ "blue-square", "direction", "top" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23eb" src="23eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_double_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ec" src="23ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_right: {
+    keywords: [ "blue-square", "next" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27a1\ufe0f" src="27a1.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_left: {
+    keywords: [ "blue-square", "previous", "back" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b05\ufe0f" src="2b05.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up: {
+    keywords: [ "blue-square", "continue", "top", "direction" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b06\ufe0f" src="2b06.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b07\ufe0f" src="2b07.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_upper_right: {
+    keywords: [ "blue-square", "point", "direction", "diagonal", "northeast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2197\ufe0f" src="2197.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_lower_right: {
+    keywords: [ "blue-square", "direction", "diagonal", "southeast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2198\ufe0f" src="2198.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_lower_left: {
+    keywords: [ "blue-square", "direction", "diagonal", "southwest" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2199\ufe0f" src="2199.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_upper_left: {
+    keywords: [ "blue-square", "point", "direction", "diagonal", "northwest" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2196\ufe0f" src="2196.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up_down: {
+    keywords: [ "blue-square", "direction", "way", "vertical" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2195\ufe0f" src="2195.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_right_arrow: {
+    keywords: [ "shape", "direction", "horizontal", "sideways" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2194\ufe0f" src="2194.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrows_counterclockwise: {
+    keywords: [ "blue-square", "sync", "cycle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd04" src="1f504.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_right_hook: {
+    keywords: [ "blue-square", "return", "rotate", "direction" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u21aa\ufe0f" src="21aa.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  leftwards_arrow_with_hook: {
+    keywords: [ "back", "return", "blue-square", "undo", "enter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u21a9\ufe0f" src="21a9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_heading_up: {
+    keywords: [ "blue-square", "direction", "top" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2934\ufe0f" src="2934.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_heading_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2935\ufe0f" src="2935.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hash: {
+    keywords: [ "symbol", "blue-square", "twitter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="#\ufe0f\u20e3" src="23-20e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  information_source: {
+    keywords: [ "blue-square", "alphabet", "letter" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2139\ufe0f" src="2139.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  abc: {
+    keywords: [ "blue-square", "alphabet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd24" src="1f524.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  abcd: {
+    keywords: [ "blue-square", "alphabet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd21" src="1f521.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  capital_abcd: {
+    keywords: [ "alphabet", "words", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd20" src="1f520.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  symbols: {
+    keywords: [ "blue-square", "music", "note", "ampersand", "percent", "glyphs", "characters" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd23" src="1f523.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  musical_note: {
+    keywords: [ "score", "tone", "sound" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb5" src="1f3b5.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  notes: {
+    keywords: [ "music", "score" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb6" src="1f3b6.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wavy_dash: {
+    keywords: [ "draw", "line", "moustache", "mustache", "squiggle", "scribble" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3030\ufe0f" src="3030.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  curly_loop: {
+    keywords: [ "scribble", "draw", "shape", "squiggle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27b0" src="27b0.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_check_mark: {
+    keywords: [ "ok", "nike", "answer", "yes", "tick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2714\ufe0f" src="2714.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrows_clockwise: {
+    keywords: [ "sync", "cycle", "round", "repeat" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd03" src="1f503.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_plus_sign: {
+    keywords: [ "math", "calculation", "addition", "more", "increase" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2795" src="2795.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_minus_sign: {
+    keywords: [ "math", "calculation", "subtract", "less" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2796" src="2796.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_division_sign: {
+    keywords: [ "divide", "math", "calculation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2797" src="2797.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_multiplication_x: {
+    keywords: [ "math", "calculation" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2716\ufe0f" src="2716.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  infinity: {
+    keywords: [ "forever" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267e" src="267e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_dollar_sign: {
+    keywords: [ "money", "sales", "payment", "currency", "buck" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb2" src="1f4b2.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  currency_exchange: {
+    keywords: [ "money", "sales", "dollar", "travel" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcb1" src="1f4b1.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  copyright: {
+    keywords: [ "ip", "license", "circle", "law", "legal" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\xa9\ufe0f" src="a9.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  registered: {
+    keywords: [ "alphabet", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\xae\ufe0f" src="ae.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  tm: {
+    keywords: [ "trademark", "brand", "law", "legal" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2122\ufe0f" src="2122.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  end: {
+    keywords: [ "words", "arrow" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1a" src="1f51a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  back: {
+    keywords: [ "arrow", "words", "return" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd19" src="1f519.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  on: {
+    keywords: [ "arrow", "words" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1b" src="1f51b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  top: {
+    keywords: [ "words", "blue-square" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1d" src="1f51d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  soon: {
+    keywords: [ "arrow", "words" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd1c" src="1f51c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ballot_box_with_check: {
+    keywords: [ "ok", "agree", "confirm", "black-square", "vote", "election", "yes", "tick" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2611\ufe0f" src="2611.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  radio_button: {
+    keywords: [ "input", "old", "music", "circle" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd18" src="1f518.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_circle: {
+    keywords: [ "shape", "round" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26aa" src="26aa.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_circle: {
+    keywords: [ "shape", "button", "round" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ab" src="26ab.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  red_circle: {
+    keywords: [ "shape", "error", "danger" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd34" src="1f534.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_blue_circle: {
+    keywords: [ "shape", "icon", "button" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd35" src="1f535.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_orange_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd38" src="1f538.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_blue_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd39" src="1f539.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_orange_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd36" src="1f536.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_blue_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd37" src="1f537.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_red_triangle: {
+    keywords: [ "shape", "direction", "up", "top" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd3a" src="1f53a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_small_square: {
+    keywords: [ "shape", "icon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25aa\ufe0f" src="25aa.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_small_square: {
+    keywords: [ "shape", "icon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25ab\ufe0f" src="25ab.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_large_square: {
+    keywords: [ "shape", "icon", "button" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b1b" src="2b1b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_large_square: {
+    keywords: [ "shape", "icon", "stone", "button" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b1c" src="2b1c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_red_triangle_down: {
+    keywords: [ "shape", "direction", "bottom" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd3b" src="1f53b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_medium_square: {
+    keywords: [ "shape", "button", "icon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fc\ufe0f" src="25fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_medium_square: {
+    keywords: [ "shape", "stone", "icon" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fb\ufe0f" src="25fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_medium_small_square: {
+    keywords: [ "icon", "shape", "button" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fe" src="25fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_medium_small_square: {
+    keywords: [ "shape", "stone", "icon", "button" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fd" src="25fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_square_button: {
+    keywords: [ "shape", "input", "frame" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd32" src="1f532.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_square_button: {
+    keywords: [ "shape", "input" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd33" src="1f533.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  speaker: {
+    keywords: [ "sound", "volume", "silence", "broadcast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd08" src="1f508.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sound: {
+    keywords: [ "volume", "speaker", "broadcast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd09" src="1f509.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loud_sound: {
+    keywords: [ "volume", "noise", "noisy", "speaker", "broadcast" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd0a" src="1f50a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mute: {
+    keywords: [ "sound", "volume", "silence", "quiet" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd07" src="1f507.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mega: {
+    keywords: [ "sound", "speaker", "volume" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce3" src="1f4e3.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loudspeaker: {
+    keywords: [ "volume", "sound" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udce2" src="1f4e2.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  bell: {
+    keywords: [ "sound", "notification", "christmas", "xmas", "chime" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd14" src="1f514.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_bell: {
+    keywords: [ "sound", "volume", "mute", "quiet", "silent" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd15" src="1f515.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_joker: {
+    keywords: [ "poker", "cards", "game", "play", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udccf" src="1f0cf.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mahjong: {
+    keywords: [ "game", "play", "chinese", "kanji" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udc04" src="1f004.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  spades: {
+    keywords: [ "poker", "cards", "suits", "magic" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2660\ufe0f" src="2660.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clubs: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2663\ufe0f" src="2663.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hearts: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2665\ufe0f" src="2665.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  diamonds: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2666\ufe0f" src="2666.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  flower_playing_cards: {
+    keywords: [ "game", "sunset", "red" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udfb4" src="1f3b4.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  thought_balloon: {
+    keywords: [ "bubble", "cloud", "speech", "thinking", "dream" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcad" src="1f4ad.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  right_anger_bubble: {
+    keywords: [ "caption", "speech", "thinking", "mad" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\uddef" src="1f5ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  speech_balloon: {
+    keywords: [ "bubble", "words", "message", "talk", "chatting" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udcac" src="1f4ac.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_speech_bubble: {
+    keywords: [ "words", "message", "talk", "chatting" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udde8" src="1f5e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd50" src="1f550.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock2: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd51" src="1f551.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock3: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd52" src="1f552.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock4: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd53" src="1f553.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock5: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd54" src="1f554.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock6: {
+    keywords: [ "time", "late", "early", "schedule", "dawn", "dusk" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd55" src="1f555.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock7: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd56" src="1f556.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock8: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd57" src="1f557.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock9: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd58" src="1f558.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock10: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd59" src="1f559.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock11: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5a" src="1f55a.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock12: {
+    keywords: [ "time", "noon", "midnight", "midday", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5b" src="1f55b.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock130: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5c" src="1f55c.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock230: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5d" src="1f55d.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock330: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5e" src="1f55e.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock430: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd5f" src="1f55f.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock530: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd60" src="1f560.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock630: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd61" src="1f561.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock730: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd62" src="1f562.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock830: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd63" src="1f563.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock930: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd64" src="1f564.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1030: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd65" src="1f565.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1130: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd66" src="1f566.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1230: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83d\udd67" src="1f567.png"/>',
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  afghanistan: {
+    keywords: [ "af", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddeb" src="1f1e6-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  aland_islands: {
+    keywords: [ "\xc5land", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddfd" src="1f1e6-1f1fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  albania: {
+    keywords: [ "al", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf1" src="1f1e6-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  algeria: {
+    keywords: [ "dz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddff" src="1f1e9-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  american_samoa: {
+    keywords: [ "american", "ws", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf8" src="1f1e6-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  andorra: {
+    keywords: [ "ad", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\udde9" src="1f1e6-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  angola: {
+    keywords: [ "ao", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf4" src="1f1e6-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  anguilla: {
+    keywords: [ "ai", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddee" src="1f1e6-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  antarctica: {
+    keywords: [ "aq", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf6" src="1f1e6-1f1f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  antigua_barbuda: {
+    keywords: [ "antigua", "barbuda", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddec" src="1f1e6-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  argentina: {
+    keywords: [ "ar", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf7" src="1f1e6-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  armenia: {
+    keywords: [ "am", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf2" src="1f1e6-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  aruba: {
+    keywords: [ "aw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddfc" src="1f1e6-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  australia: {
+    keywords: [ "au", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddfa" src="1f1e6-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  austria: {
+    keywords: [ "at", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddf9" src="1f1e6-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  azerbaijan: {
+    keywords: [ "az", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddff" src="1f1e6-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bahamas: {
+    keywords: [ "bs", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf8" src="1f1e7-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bahrain: {
+    keywords: [ "bh", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\udded" src="1f1e7-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bangladesh: {
+    keywords: [ "bd", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\udde9" src="1f1e7-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  barbados: {
+    keywords: [ "bb", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\udde7" src="1f1e7-1f1e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belarus: {
+    keywords: [ "by", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddfe" src="1f1e7-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belgium: {
+    keywords: [ "be", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddea" src="1f1e7-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belize: {
+    keywords: [ "bz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddff" src="1f1e7-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  benin: {
+    keywords: [ "bj", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddef" src="1f1e7-1f1ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bermuda: {
+    keywords: [ "bm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf2" src="1f1e7-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bhutan: {
+    keywords: [ "bt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf9" src="1f1e7-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bolivia: {
+    keywords: [ "bo", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf4" src="1f1e7-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  caribbean_netherlands: {
+    keywords: [ "bonaire", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf6" src="1f1e7-1f1f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bosnia_herzegovina: {
+    keywords: [ "bosnia", "herzegovina", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\udde6" src="1f1e7-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  botswana: {
+    keywords: [ "bw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddfc" src="1f1e7-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  brazil: {
+    keywords: [ "br", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf7" src="1f1e7-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  british_indian_ocean_territory: {
+    keywords: [ "british", "indian", "ocean", "territory", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf4" src="1f1ee-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  british_virgin_islands: {
+    keywords: [ "british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\uddec" src="1f1fb-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  brunei: {
+    keywords: [ "bn", "darussalam", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf3" src="1f1e7-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bulgaria: {
+    keywords: [ "bg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddec" src="1f1e7-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  burkina_faso: {
+    keywords: [ "burkina", "faso", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddeb" src="1f1e7-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  burundi: {
+    keywords: [ "bi", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddee" src="1f1e7-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cape_verde: {
+    keywords: [ "cabo", "verde", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddfb" src="1f1e8-1f1fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cambodia: {
+    keywords: [ "kh", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\udded" src="1f1f0-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cameroon: {
+    keywords: [ "cm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf2" src="1f1e8-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  canada: {
+    keywords: [ "ca", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\udde6" src="1f1e8-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  canary_islands: {
+    keywords: [ "canary", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\udde8" src="1f1ee-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cayman_islands: {
+    keywords: [ "cayman", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddfe" src="1f1f0-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  central_african_republic: {
+    keywords: [ "central", "african", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddeb" src="1f1e8-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  chad: {
+    keywords: [ "td", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\udde9" src="1f1f9-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  chile: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf1" src="1f1e8-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cn: {
+    keywords: [ "china", "chinese", "prc", "flag", "country", "nation", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf3" src="1f1e8-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  christmas_island: {
+    keywords: [ "christmas", "island", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddfd" src="1f1e8-1f1fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cocos_islands: {
+    keywords: [ "cocos", "keeling", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\udde8" src="1f1e8-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  colombia: {
+    keywords: [ "co", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf4" src="1f1e8-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  comoros: {
+    keywords: [ "km", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddf2" src="1f1f0-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  congo_brazzaville: {
+    keywords: [ "congo", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddec" src="1f1e8-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  congo_kinshasa: {
+    keywords: [ "congo", "democratic", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\udde9" src="1f1e8-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cook_islands: {
+    keywords: [ "cook", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf0" src="1f1e8-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  costa_rica: {
+    keywords: [ "costa", "rica", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddf7" src="1f1e8-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  croatia: {
+    keywords: [ "hr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udded\ud83c\uddf7" src="1f1ed-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cuba: {
+    keywords: [ "cu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddfa" src="1f1e8-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  curacao: {
+    keywords: [ "cura\xe7ao", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddfc" src="1f1e8-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cyprus: {
+    keywords: [ "cy", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddfe" src="1f1e8-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  czech_republic: {
+    keywords: [ "cz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddff" src="1f1e8-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  denmark: {
+    keywords: [ "dk", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddf0" src="1f1e9-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  djibouti: {
+    keywords: [ "dj", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddef" src="1f1e9-1f1ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  dominica: {
+    keywords: [ "dm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddf2" src="1f1e9-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  dominican_republic: {
+    keywords: [ "dominican", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddf4" src="1f1e9-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ecuador: {
+    keywords: [ "ec", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\udde8" src="1f1ea-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  egypt: {
+    keywords: [ "eg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddec" src="1f1ea-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  el_salvador: {
+    keywords: [ "el", "salvador", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddfb" src="1f1f8-1f1fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  equatorial_guinea: {
+    keywords: [ "equatorial", "gn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf6" src="1f1ec-1f1f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  eritrea: {
+    keywords: [ "er", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddf7" src="1f1ea-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  estonia: {
+    keywords: [ "ee", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddea" src="1f1ea-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ethiopia: {
+    keywords: [ "et", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddf9" src="1f1ea-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  eu: {
+    keywords: [ "european", "union", "flag", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddfa" src="1f1ea-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  falkland_islands: {
+    keywords: [ "falkland", "islands", "malvinas", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddf0" src="1f1eb-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  faroe_islands: {
+    keywords: [ "faroe", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddf4" src="1f1eb-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  fiji: {
+    keywords: [ "fj", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddef" src="1f1eb-1f1ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  finland: {
+    keywords: [ "fi", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddee" src="1f1eb-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  fr: {
+    keywords: [ "banner", "flag", "nation", "france", "french", "country" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddf7" src="1f1eb-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_guiana: {
+    keywords: [ "french", "guiana", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddeb" src="1f1ec-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_polynesia: {
+    keywords: [ "french", "polynesia", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddeb" src="1f1f5-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_southern_territories: {
+    keywords: [ "french", "southern", "territories", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddeb" src="1f1f9-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gabon: {
+    keywords: [ "ga", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\udde6" src="1f1ec-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gambia: {
+    keywords: [ "gm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf2" src="1f1ec-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  georgia: {
+    keywords: [ "ge", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddea" src="1f1ec-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  de: {
+    keywords: [ "german", "nation", "flag", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde9\ud83c\uddea" src="1f1e9-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ghana: {
+    keywords: [ "gh", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\udded" src="1f1ec-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gibraltar: {
+    keywords: [ "gi", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddee" src="1f1ec-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  greece: {
+    keywords: [ "gr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf7" src="1f1ec-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  greenland: {
+    keywords: [ "gl", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf1" src="1f1ec-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  grenada: {
+    keywords: [ "gd", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\udde9" src="1f1ec-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guadeloupe: {
+    keywords: [ "gp", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf5" src="1f1ec-1f1f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guam: {
+    keywords: [ "gu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddfa" src="1f1ec-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guatemala: {
+    keywords: [ "gt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf9" src="1f1ec-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guernsey: {
+    keywords: [ "gg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddec" src="1f1ec-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guinea: {
+    keywords: [ "gn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf3" src="1f1ec-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guinea_bissau: {
+    keywords: [ "gw", "bissau", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddfc" src="1f1ec-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guyana: {
+    keywords: [ "gy", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddfe" src="1f1ec-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  haiti: {
+    keywords: [ "ht", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udded\ud83c\uddf9" src="1f1ed-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  honduras: {
+    keywords: [ "hn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udded\ud83c\uddf3" src="1f1ed-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  hong_kong: {
+    keywords: [ "hong", "kong", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udded\ud83c\uddf0" src="1f1ed-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  hungary: {
+    keywords: [ "hu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udded\ud83c\uddfa" src="1f1ed-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iceland: {
+    keywords: [ "is", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf8" src="1f1ee-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  india: {
+    keywords: [ "in", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf3" src="1f1ee-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  indonesia: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\udde9" src="1f1ee-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iran: {
+    keywords: [ "iran,", "islamic", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf7" src="1f1ee-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iraq: {
+    keywords: [ "iq", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf6" src="1f1ee-1f1f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ireland: {
+    keywords: [ "ie", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddea" src="1f1ee-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  isle_of_man: {
+    keywords: [ "isle", "man", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf2" src="1f1ee-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  israel: {
+    keywords: [ "il", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf1" src="1f1ee-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  it: {
+    keywords: [ "italy", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddee\ud83c\uddf9" src="1f1ee-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cote_divoire: {
+    keywords: [ "ivory", "coast", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\uddee" src="1f1e8-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jamaica: {
+    keywords: [ "jm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddef\ud83c\uddf2" src="1f1ef-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jp: {
+    keywords: [ "japanese", "nation", "flag", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddef\ud83c\uddf5" src="1f1ef-1f1f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jersey: {
+    keywords: [ "je", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddef\ud83c\uddea" src="1f1ef-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jordan: {
+    keywords: [ "jo", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddef\ud83c\uddf4" src="1f1ef-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kazakhstan: {
+    keywords: [ "kz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddff" src="1f1f0-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kenya: {
+    keywords: [ "ke", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddea" src="1f1f0-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kiribati: {
+    keywords: [ "ki", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddee" src="1f1f0-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kosovo: {
+    keywords: [ "xk", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfd\ud83c\uddf0" src="1f1fd-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kuwait: {
+    keywords: [ "kw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddfc" src="1f1f0-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kyrgyzstan: {
+    keywords: [ "kg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddec" src="1f1f0-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  laos: {
+    keywords: [ "lao", "democratic", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\udde6" src="1f1f1-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  latvia: {
+    keywords: [ "lv", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddfb" src="1f1f1-1f1fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lebanon: {
+    keywords: [ "lb", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\udde7" src="1f1f1-1f1e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lesotho: {
+    keywords: [ "ls", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddf8" src="1f1f1-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  liberia: {
+    keywords: [ "lr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddf7" src="1f1f1-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  libya: {
+    keywords: [ "ly", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddfe" src="1f1f1-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  liechtenstein: {
+    keywords: [ "li", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddee" src="1f1f1-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lithuania: {
+    keywords: [ "lt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddf9" src="1f1f1-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  luxembourg: {
+    keywords: [ "lu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddfa" src="1f1f1-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  macau: {
+    keywords: [ "macao", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf4" src="1f1f2-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  macedonia: {
+    keywords: [ "macedonia,", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf0" src="1f1f2-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  madagascar: {
+    keywords: [ "mg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddec" src="1f1f2-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malawi: {
+    keywords: [ "mw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddfc" src="1f1f2-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malaysia: {
+    keywords: [ "my", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddfe" src="1f1f2-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  maldives: {
+    keywords: [ "mv", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddfb" src="1f1f2-1f1fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mali: {
+    keywords: [ "ml", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf1" src="1f1f2-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malta: {
+    keywords: [ "mt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf9" src="1f1f2-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  marshall_islands: {
+    keywords: [ "marshall", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\udded" src="1f1f2-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  martinique: {
+    keywords: [ "mq", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf6" src="1f1f2-1f1f6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mauritania: {
+    keywords: [ "mr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf7" src="1f1f2-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mauritius: {
+    keywords: [ "mu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddfa" src="1f1f2-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mayotte: {
+    keywords: [ "yt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfe\ud83c\uddf9" src="1f1fe-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mexico: {
+    keywords: [ "mx", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddfd" src="1f1f2-1f1fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  micronesia: {
+    keywords: [ "micronesia,", "federated", "states", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddeb\ud83c\uddf2" src="1f1eb-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  moldova: {
+    keywords: [ "moldova,", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\udde9" src="1f1f2-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  monaco: {
+    keywords: [ "mc", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\udde8" src="1f1f2-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mongolia: {
+    keywords: [ "mn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf3" src="1f1f2-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  montenegro: {
+    keywords: [ "me", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddea" src="1f1f2-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  montserrat: {
+    keywords: [ "ms", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf8" src="1f1f2-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  morocco: {
+    keywords: [ "ma", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\udde6" src="1f1f2-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mozambique: {
+    keywords: [ "mz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddff" src="1f1f2-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  myanmar: {
+    keywords: [ "mm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf2" src="1f1f2-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  namibia: {
+    keywords: [ "na", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\udde6" src="1f1f3-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nauru: {
+    keywords: [ "nr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddf7" src="1f1f3-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nepal: {
+    keywords: [ "np", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddf5" src="1f1f3-1f1f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  netherlands: {
+    keywords: [ "nl", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddf1" src="1f1f3-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  new_caledonia: {
+    keywords: [ "new", "caledonia", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\udde8" src="1f1f3-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  new_zealand: {
+    keywords: [ "new", "zealand", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddff" src="1f1f3-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nicaragua: {
+    keywords: [ "ni", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddee" src="1f1f3-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  niger: {
+    keywords: [ "ne", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddea" src="1f1f3-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nigeria: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddec" src="1f1f3-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  niue: {
+    keywords: [ "nu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddfa" src="1f1f3-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  norfolk_island: {
+    keywords: [ "norfolk", "island", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddeb" src="1f1f3-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  northern_mariana_islands: {
+    keywords: [ "northern", "mariana", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf2\ud83c\uddf5" src="1f1f2-1f1f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  north_korea: {
+    keywords: [ "north", "korea", "nation", "flag", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddf5" src="1f1f0-1f1f5.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  norway: {
+    keywords: [ "no", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf3\ud83c\uddf4" src="1f1f3-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  oman: {
+    keywords: [ "om_symbol", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf4\ud83c\uddf2" src="1f1f4-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pakistan: {
+    keywords: [ "pk", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf0" src="1f1f5-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  palau: {
+    keywords: [ "pw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddfc" src="1f1f5-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  palestinian_territories: {
+    keywords: [ "palestine", "palestinian", "territories", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf8" src="1f1f5-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  panama: {
+    keywords: [ "pa", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\udde6" src="1f1f5-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  papua_new_guinea: {
+    keywords: [ "papua", "new", "guinea", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddec" src="1f1f5-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  paraguay: {
+    keywords: [ "py", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddfe" src="1f1f5-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  peru: {
+    keywords: [ "pe", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddea" src="1f1f5-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  philippines: {
+    keywords: [ "ph", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\udded" src="1f1f5-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pitcairn_islands: {
+    keywords: [ "pitcairn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf3" src="1f1f5-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  poland: {
+    keywords: [ "pl", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf1" src="1f1f5-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  portugal: {
+    keywords: [ "pt", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf9" src="1f1f5-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  puerto_rico: {
+    keywords: [ "puerto", "rico", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf7" src="1f1f5-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  qatar: {
+    keywords: [ "qa", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf6\ud83c\udde6" src="1f1f6-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  reunion: {
+    keywords: [ "r\xe9union", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf7\ud83c\uddea" src="1f1f7-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  romania: {
+    keywords: [ "ro", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf7\ud83c\uddf4" src="1f1f7-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ru: {
+    keywords: [ "russian", "federation", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf7\ud83c\uddfa" src="1f1f7-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  rwanda: {
+    keywords: [ "rw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf7\ud83c\uddfc" src="1f1f7-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_barthelemy: {
+    keywords: [ "saint", "barth\xe9lemy", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde7\ud83c\uddf1" src="1f1e7-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_helena: {
+    keywords: [ "saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\udded" src="1f1f8-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_kitts_nevis: {
+    keywords: [ "saint", "kitts", "nevis", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddf3" src="1f1f0-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_lucia: {
+    keywords: [ "saint", "lucia", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\udde8" src="1f1f1-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_pierre_miquelon: {
+    keywords: [ "saint", "pierre", "miquelon", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf5\ud83c\uddf2" src="1f1f5-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_vincent_grenadines: {
+    keywords: [ "saint", "vincent", "grenadines", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\udde8" src="1f1fb-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  samoa: {
+    keywords: [ "ws", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfc\ud83c\uddf8" src="1f1fc-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  san_marino: {
+    keywords: [ "san", "marino", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf2" src="1f1f8-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sao_tome_principe: {
+    keywords: [ "sao", "tome", "principe", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf9" src="1f1f8-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  saudi_arabia: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\udde6" src="1f1f8-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  senegal: {
+    keywords: [ "sn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf3" src="1f1f8-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  serbia: {
+    keywords: [ "rs", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf7\ud83c\uddf8" src="1f1f7-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  seychelles: {
+    keywords: [ "sc", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\udde8" src="1f1f8-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sierra_leone: {
+    keywords: [ "sierra", "leone", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf1" src="1f1f8-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  singapore: {
+    keywords: [ "sg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddec" src="1f1f8-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sint_maarten: {
+    keywords: [ "sint", "maarten", "dutch", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddfd" src="1f1f8-1f1fd.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  slovakia: {
+    keywords: [ "sk", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf0" src="1f1f8-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  slovenia: {
+    keywords: [ "si", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddee" src="1f1f8-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  solomon_islands: {
+    keywords: [ "solomon", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\udde7" src="1f1f8-1f1e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  somalia: {
+    keywords: [ "so", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf4" src="1f1f8-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_africa: {
+    keywords: [ "south", "africa", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddff\ud83c\udde6" src="1f1ff-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_georgia_south_sandwich_islands: {
+    keywords: [ "south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\uddf8" src="1f1ec-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kr: {
+    keywords: [ "south", "korea", "nation", "flag", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf0\ud83c\uddf7" src="1f1f0-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_sudan: {
+    keywords: [ "south", "sd", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf8" src="1f1f8-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  es: {
+    keywords: [ "spain", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\uddf8" src="1f1ea-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sri_lanka: {
+    keywords: [ "sri", "lanka", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf1\ud83c\uddf0" src="1f1f1-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sudan: {
+    keywords: [ "sd", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\udde9" src="1f1f8-1f1e9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  suriname: {
+    keywords: [ "sr", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddf7" src="1f1f8-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  swaziland: {
+    keywords: [ "sz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddff" src="1f1f8-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sweden: {
+    keywords: [ "se", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddea" src="1f1f8-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  switzerland: {
+    keywords: [ "ch", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde8\ud83c\udded" src="1f1e8-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  syria: {
+    keywords: [ "syrian", "arab", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf8\ud83c\uddfe" src="1f1f8-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  taiwan: {
+    keywords: [ "tw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddfc" src="1f1f9-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tajikistan: {
+    keywords: [ "tj", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddef" src="1f1f9-1f1ef.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tanzania: {
+    keywords: [ "tanzania,", "united", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddff" src="1f1f9-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  thailand: {
+    keywords: [ "th", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\udded" src="1f1f9-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  timor_leste: {
+    keywords: [ "timor", "leste", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf1" src="1f1f9-1f1f1.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  togo: {
+    keywords: [ "tg", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddec" src="1f1f9-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tokelau: {
+    keywords: [ "tk", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf0" src="1f1f9-1f1f0.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tonga: {
+    keywords: [ "to", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf4" src="1f1f9-1f1f4.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  trinidad_tobago: {
+    keywords: [ "trinidad", "tobago", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf9" src="1f1f9-1f1f9.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tunisia: {
+    keywords: [ "tn", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf3" src="1f1f9-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tr: {
+    keywords: [ "turkey", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf7" src="1f1f9-1f1f7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  turkmenistan: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddf2" src="1f1f9-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  turks_caicos_islands: {
+    keywords: [ "turks", "caicos", "islands", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\udde8" src="1f1f9-1f1e8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tuvalu: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddf9\ud83c\uddfb" src="1f1f9-1f1fb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uganda: {
+    keywords: [ "ug", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\uddec" src="1f1fa-1f1ec.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ukraine: {
+    keywords: [ "ua", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\udde6" src="1f1fa-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  united_arab_emirates: {
+    keywords: [ "united", "arab", "emirates", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udde6\ud83c\uddea" src="1f1e6-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uk: {
+    keywords: [ "united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddec\ud83c\udde7" src="1f1ec-1f1e7.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  england: {
+    keywords: [ "flag", "english" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f" src="1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  scotland: {
+    keywords: [ "flag", "scottish" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f" src="1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  wales: {
+    keywords: [ "flag", "welsh" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f" src="1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  us: {
+    keywords: [ "united", "states", "america", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\uddf8" src="1f1fa-1f1f8.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  us_virgin_islands: {
+    keywords: [ "virgin", "islands", "us", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\uddee" src="1f1fb-1f1ee.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uruguay: {
+    keywords: [ "uy", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\uddfe" src="1f1fa-1f1fe.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uzbekistan: {
+    keywords: [ "uz", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\uddff" src="1f1fa-1f1ff.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vanuatu: {
+    keywords: [ "vu", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\uddfa" src="1f1fb-1f1fa.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vatican_city: {
+    keywords: [ "vatican", "city", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\udde6" src="1f1fb-1f1e6.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  venezuela: {
+    keywords: [ "ve", "bolivarian", "republic", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\uddea" src="1f1fb-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vietnam: {
+    keywords: [ "viet", "nam", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfb\ud83c\uddf3" src="1f1fb-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  wallis_futuna: {
+    keywords: [ "wallis", "futuna", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfc\ud83c\uddeb" src="1f1fc-1f1eb.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  western_sahara: {
+    keywords: [ "western", "sahara", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddea\ud83c\udded" src="1f1ea-1f1ed.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  yemen: {
+    keywords: [ "ye", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfe\ud83c\uddea" src="1f1fe-1f1ea.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  zambia: {
+    keywords: [ "zm", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddff\ud83c\uddf2" src="1f1ff-1f1f2.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  zimbabwe: {
+    keywords: [ "zw", "flag", "nation", "country", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddff\ud83c\uddfc" src="1f1ff-1f1fc.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  united_nations: {
+    keywords: [ "un", "flag", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\uddfa\ud83c\uddf3" src="1f1fa-1f1f3.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pirate_flag: {
+    keywords: [ "skull", "crossbones", "flag", "banner" ],
+    "char": '<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\ud83c\udff4\u200d\u2620\ufe0f" src="1f3f4-200d-2620-fe0f.png"/>',
+    fitzpatrick_scale: false,
+    category: "flags"
+  }
+});

File diff suppressed because it is too large
+ 2 - 0
public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojiimages.min.js


+ 9423 - 0
public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojis.js

@@ -0,0 +1,9423 @@
+// Source: npm package: emojilib, file:emojis.json
+window.tinymce.Resource.add("tinymce.plugins.emoticons", {
+  grinning: {
+    keywords: [ "face", "smile", "happy", "joy", ":D", "grin" ],
+    "char": "\ud83d\ude00",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  grimacing: {
+    keywords: [ "face", "grimace", "teeth" ],
+    "char": "\ud83d\ude2c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  grin: {
+    keywords: [ "face", "happy", "smile", "joy", "kawaii" ],
+    "char": "\ud83d\ude01",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  joy: {
+    keywords: [ "face", "cry", "tears", "weep", "happy", "happytears", "haha" ],
+    "char": "\ud83d\ude02",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rofl: {
+    keywords: [ "face", "rolling", "floor", "laughing", "lol", "haha" ],
+    "char": "\ud83e\udd23",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  partying: {
+    keywords: [ "face", "celebration", "woohoo" ],
+    "char": "\ud83e\udd73",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiley: {
+    keywords: [ "face", "happy", "joy", "haha", ":D", ":)", "smile", "funny" ],
+    "char": "\ud83d\ude03",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smile: {
+    keywords: [ "face", "happy", "joy", "funny", "haha", "laugh", "like", ":D", ":)" ],
+    "char": "\ud83d\ude04",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sweat_smile: {
+    keywords: [ "face", "hot", "happy", "laugh", "sweat", "smile", "relief" ],
+    "char": "\ud83d\ude05",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  laughing: {
+    keywords: [ "happy", "joy", "lol", "satisfied", "haha", "face", "glad", "XD", "laugh" ],
+    "char": "\ud83d\ude06",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  innocent: {
+    keywords: [ "face", "angel", "heaven", "halo" ],
+    "char": "\ud83d\ude07",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  wink: {
+    keywords: [ "face", "happy", "mischievous", "secret", ";)", "smile", "eye" ],
+    "char": "\ud83d\ude09",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  blush: {
+    keywords: [ "face", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy" ],
+    "char": "\ud83d\ude0a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  slightly_smiling_face: {
+    keywords: [ "face", "smile" ],
+    "char": "\ud83d\ude42",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  upside_down_face: {
+    keywords: [ "face", "flipped", "silly", "smile" ],
+    "char": "\ud83d\ude43",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  relaxed: {
+    keywords: [ "face", "blush", "massage", "happiness" ],
+    "char": "\u263a\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  yum: {
+    keywords: [ "happy", "joy", "tongue", "smile", "face", "silly", "yummy", "nom", "delicious", "savouring" ],
+    "char": "\ud83d\ude0b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  relieved: {
+    keywords: [ "face", "relaxed", "phew", "massage", "happiness" ],
+    "char": "\ud83d\ude0c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  heart_eyes: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "crush", "heart" ],
+    "char": "\ud83d\ude0d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiling_face_with_three_hearts: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "crush", "hearts", "adore" ],
+    "char": "\ud83e\udd70",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_heart: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "kiss" ],
+    "char": "\ud83d\ude18",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing: {
+    keywords: [ "love", "like", "face", "3", "valentines", "infatuation", "kiss" ],
+    "char": "\ud83d\ude17",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_smiling_eyes: {
+    keywords: [ "face", "affection", "valentines", "infatuation", "kiss" ],
+    "char": "\ud83d\ude19",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_closed_eyes: {
+    keywords: [ "face", "love", "like", "affection", "valentines", "infatuation", "kiss" ],
+    "char": "\ud83d\ude1a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue_winking_eye: {
+    keywords: [ "face", "prank", "childish", "playful", "mischievous", "smile", "wink", "tongue" ],
+    "char": "\ud83d\ude1c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zany: {
+    keywords: [ "face", "goofy", "crazy" ],
+    "char": "\ud83e\udd2a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  raised_eyebrow: {
+    keywords: [ "face", "distrust", "scepticism", "disapproval", "disbelief", "surprise" ],
+    "char": "\ud83e\udd28",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  monocle: {
+    keywords: [ "face", "stuffy", "wealthy" ],
+    "char": "\ud83e\uddd0",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue_closed_eyes: {
+    keywords: [ "face", "prank", "playful", "mischievous", "smile", "tongue" ],
+    "char": "\ud83d\ude1d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  stuck_out_tongue: {
+    keywords: [ "face", "prank", "childish", "playful", "mischievous", "smile", "tongue" ],
+    "char": "\ud83d\ude1b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  money_mouth_face: {
+    keywords: [ "face", "rich", "dollar", "money" ],
+    "char": "\ud83e\udd11",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  nerd_face: {
+    keywords: [ "face", "nerdy", "geek", "dork" ],
+    "char": "\ud83e\udd13",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sunglasses: {
+    keywords: [ "face", "cool", "smile", "summer", "beach", "sunglass" ],
+    "char": "\ud83d\ude0e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  star_struck: {
+    keywords: [ "face", "smile", "starry", "eyes", "grinning" ],
+    "char": "\ud83e\udd29",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  clown_face: {
+    keywords: [ "face" ],
+    "char": "\ud83e\udd21",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cowboy_hat_face: {
+    keywords: [ "face", "cowgirl", "hat" ],
+    "char": "\ud83e\udd20",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hugs: {
+    keywords: [ "face", "smile", "hug" ],
+    "char": "\ud83e\udd17",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smirk: {
+    keywords: [ "face", "smile", "mean", "prank", "smug", "sarcasm" ],
+    "char": "\ud83d\ude0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  no_mouth: {
+    keywords: [ "face", "hellokitty" ],
+    "char": "\ud83d\ude36",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  neutral_face: {
+    keywords: [ "indifference", "meh", ":|", "neutral" ],
+    "char": "\ud83d\ude10",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  expressionless: {
+    keywords: [ "face", "indifferent", "-_-", "meh", "deadpan" ],
+    "char": "\ud83d\ude11",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  unamused: {
+    keywords: [ "indifference", "bored", "straight face", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "side_eye" ],
+    "char": "\ud83d\ude12",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  roll_eyes: {
+    keywords: [ "face", "eyeroll", "frustrated" ],
+    "char": "\ud83d\ude44",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  thinking: {
+    keywords: [ "face", "hmmm", "think", "consider" ],
+    "char": "\ud83e\udd14",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  lying_face: {
+    keywords: [ "face", "lie", "pinocchio" ],
+    "char": "\ud83e\udd25",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hand_over_mouth: {
+    keywords: [ "face", "whoops", "shock", "surprise" ],
+    "char": "\ud83e\udd2d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  shushing: {
+    keywords: [ "face", "quiet", "shhh" ],
+    "char": "\ud83e\udd2b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  symbols_over_mouth: {
+    keywords: [ "face", "swearing", "cursing", "cussing", "profanity", "expletive" ],
+    "char": "\ud83e\udd2c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  exploding_head: {
+    keywords: [ "face", "shocked", "mind", "blown" ],
+    "char": "\ud83e\udd2f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  flushed: {
+    keywords: [ "face", "blush", "shy", "flattered" ],
+    "char": "\ud83d\ude33",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  disappointed: {
+    keywords: [ "face", "sad", "upset", "depressed", ":(" ],
+    "char": "\ud83d\ude1e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  worried: {
+    keywords: [ "face", "concern", "nervous", ":(" ],
+    "char": "\ud83d\ude1f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  angry: {
+    keywords: [ "mad", "face", "annoyed", "frustrated" ],
+    "char": "\ud83d\ude20",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rage: {
+    keywords: [ "angry", "mad", "hate", "despise" ],
+    "char": "\ud83d\ude21",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pensive: {
+    keywords: [ "face", "sad", "depressed", "upset" ],
+    "char": "\ud83d\ude14",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  confused: {
+    keywords: [ "face", "indifference", "huh", "weird", "hmmm", ":/" ],
+    "char": "\ud83d\ude15",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  slightly_frowning_face: {
+    keywords: [ "face", "frowning", "disappointed", "sad", "upset" ],
+    "char": "\ud83d\ude41",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  frowning_face: {
+    keywords: [ "face", "sad", "upset", "frown" ],
+    "char": "\u2639",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  persevere: {
+    keywords: [ "face", "sick", "no", "upset", "oops" ],
+    "char": "\ud83d\ude23",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  confounded: {
+    keywords: [ "face", "confused", "sick", "unwell", "oops", ":S" ],
+    "char": "\ud83d\ude16",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tired_face: {
+    keywords: [ "sick", "whine", "upset", "frustrated" ],
+    "char": "\ud83d\ude2b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  weary: {
+    keywords: [ "face", "tired", "sleepy", "sad", "frustrated", "upset" ],
+    "char": "\ud83d\ude29",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pleading: {
+    keywords: [ "face", "begging", "mercy" ],
+    "char": "\ud83e\udd7a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  triumph: {
+    keywords: [ "face", "gas", "phew", "proud", "pride" ],
+    "char": "\ud83d\ude24",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  open_mouth: {
+    keywords: [ "face", "surprise", "impressed", "wow", "whoa", ":O" ],
+    "char": "\ud83d\ude2e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scream: {
+    keywords: [ "face", "munch", "scared", "omg" ],
+    "char": "\ud83d\ude31",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  fearful: {
+    keywords: [ "face", "scared", "terrified", "nervous", "oops", "huh" ],
+    "char": "\ud83d\ude28",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cold_sweat: {
+    keywords: [ "face", "nervous", "sweat" ],
+    "char": "\ud83d\ude30",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hushed: {
+    keywords: [ "face", "woo", "shh" ],
+    "char": "\ud83d\ude2f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  frowning: {
+    keywords: [ "face", "aw", "what" ],
+    "char": "\ud83d\ude26",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  anguished: {
+    keywords: [ "face", "stunned", "nervous" ],
+    "char": "\ud83d\ude27",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cry: {
+    keywords: [ "face", "tears", "sad", "depressed", "upset", ":'(" ],
+    "char": "\ud83d\ude22",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  disappointed_relieved: {
+    keywords: [ "face", "phew", "sweat", "nervous" ],
+    "char": "\ud83d\ude25",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  drooling_face: {
+    keywords: [ "face" ],
+    "char": "\ud83e\udd24",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sleepy: {
+    keywords: [ "face", "tired", "rest", "nap" ],
+    "char": "\ud83d\ude2a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sweat: {
+    keywords: [ "face", "hot", "sad", "tired", "exercise" ],
+    "char": "\ud83d\ude13",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hot: {
+    keywords: [ "face", "feverish", "heat", "red", "sweating" ],
+    "char": "\ud83e\udd75",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  cold: {
+    keywords: [ "face", "blue", "freezing", "frozen", "frostbite", "icicles" ],
+    "char": "\ud83e\udd76",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sob: {
+    keywords: [ "face", "cry", "tears", "sad", "upset", "depressed" ],
+    "char": "\ud83d\ude2d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dizzy_face: {
+    keywords: [ "spent", "unconscious", "xox", "dizzy" ],
+    "char": "\ud83d\ude35",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  astonished: {
+    keywords: [ "face", "xox", "surprised", "poisoned" ],
+    "char": "\ud83d\ude32",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zipper_mouth_face: {
+    keywords: [ "face", "sealed", "zipper", "secret" ],
+    "char": "\ud83e\udd10",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  nauseated_face: {
+    keywords: [ "face", "vomit", "gross", "green", "sick", "throw up", "ill" ],
+    "char": "\ud83e\udd22",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sneezing_face: {
+    keywords: [ "face", "gesundheit", "sneeze", "sick", "allergy" ],
+    "char": "\ud83e\udd27",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  vomiting: {
+    keywords: [ "face", "sick" ],
+    "char": "\ud83e\udd2e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mask: {
+    keywords: [ "face", "sick", "ill", "disease" ],
+    "char": "\ud83d\ude37",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  face_with_thermometer: {
+    keywords: [ "sick", "temperature", "thermometer", "cold", "fever" ],
+    "char": "\ud83e\udd12",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  face_with_head_bandage: {
+    keywords: [ "injured", "clumsy", "bandage", "hurt" ],
+    "char": "\ud83e\udd15",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  woozy: {
+    keywords: [ "face", "dizzy", "intoxicated", "tipsy", "wavy" ],
+    "char": "\ud83e\udd74",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sleeping: {
+    keywords: [ "face", "tired", "sleepy", "night", "zzz" ],
+    "char": "\ud83d\ude34",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  zzz: {
+    keywords: [ "sleepy", "tired", "dream" ],
+    "char": "\ud83d\udca4",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  poop: {
+    keywords: [ "hankey", "shitface", "fail", "turd", "shit" ],
+    "char": "\ud83d\udca9",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiling_imp: {
+    keywords: [ "devil", "horns" ],
+    "char": "\ud83d\ude08",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  imp: {
+    keywords: [ "devil", "angry", "horns" ],
+    "char": "\ud83d\udc7f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  japanese_ogre: {
+    keywords: [ "monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon", "japanese", "ogre" ],
+    "char": "\ud83d\udc79",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  japanese_goblin: {
+    keywords: [ "red", "evil", "mask", "monster", "scary", "creepy", "japanese", "goblin" ],
+    "char": "\ud83d\udc7a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  skull: {
+    keywords: [ "dead", "skeleton", "creepy", "death" ],
+    "char": "\ud83d\udc80",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ghost: {
+    keywords: [ "halloween", "spooky", "scary" ],
+    "char": "\ud83d\udc7b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  alien: {
+    keywords: [ "UFO", "paul", "weird", "outer_space" ],
+    "char": "\ud83d\udc7d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  robot: {
+    keywords: [ "computer", "machine", "bot" ],
+    "char": "\ud83e\udd16",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smiley_cat: {
+    keywords: [ "animal", "cats", "happy", "smile" ],
+    "char": "\ud83d\ude3a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smile_cat: {
+    keywords: [ "animal", "cats", "smile" ],
+    "char": "\ud83d\ude38",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  joy_cat: {
+    keywords: [ "animal", "cats", "haha", "happy", "tears" ],
+    "char": "\ud83d\ude39",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  heart_eyes_cat: {
+    keywords: [ "animal", "love", "like", "affection", "cats", "valentines", "heart" ],
+    "char": "\ud83d\ude3b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  smirk_cat: {
+    keywords: [ "animal", "cats", "smirk" ],
+    "char": "\ud83d\ude3c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kissing_cat: {
+    keywords: [ "animal", "cats", "kiss" ],
+    "char": "\ud83d\ude3d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scream_cat: {
+    keywords: [ "animal", "cats", "munch", "scared", "scream" ],
+    "char": "\ud83d\ude40",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  crying_cat_face: {
+    keywords: [ "animal", "tears", "weep", "sad", "cats", "upset", "cry" ],
+    "char": "\ud83d\ude3f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pouting_cat: {
+    keywords: [ "animal", "cats" ],
+    "char": "\ud83d\ude3e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  palms_up: {
+    keywords: [ "hands", "gesture", "cupped", "prayer" ],
+    "char": "\ud83e\udd32",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hands: {
+    keywords: [ "gesture", "hooray", "yea", "celebration", "hands" ],
+    "char": "\ud83d\ude4c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  clap: {
+    keywords: [ "hands", "praise", "applause", "congrats", "yay" ],
+    "char": "\ud83d\udc4f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  wave: {
+    keywords: [ "hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm" ],
+    "char": "\ud83d\udc4b",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  call_me_hand: {
+    keywords: [ "hands", "gesture" ],
+    "char": "\ud83e\udd19",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  "+1": {
+    keywords: [ "thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like" ],
+    "char": "\ud83d\udc4d",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  "-1": {
+    keywords: [ "thumbsdown", "no", "dislike", "hand" ],
+    "char": "\ud83d\udc4e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  facepunch: {
+    keywords: [ "angry", "violence", "fist", "hit", "attack", "hand" ],
+    "char": "\ud83d\udc4a",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist: {
+    keywords: [ "fingers", "hand", "grasp" ],
+    "char": "\u270a",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist_left: {
+    keywords: [ "hand", "fistbump" ],
+    "char": "\ud83e\udd1b",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fist_right: {
+    keywords: [ "hand", "fistbump" ],
+    "char": "\ud83e\udd1c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  v: {
+    keywords: [ "fingers", "ohyeah", "hand", "peace", "victory", "two" ],
+    "char": "\u270c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_hand: {
+    keywords: [ "fingers", "limbs", "perfect", "ok", "okay" ],
+    "char": "\ud83d\udc4c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hand: {
+    keywords: [ "fingers", "stop", "highfive", "palm", "ban" ],
+    "char": "\u270b",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_back_of_hand: {
+    keywords: [ "fingers", "raised", "backhand" ],
+    "char": "\ud83e\udd1a",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  open_hands: {
+    keywords: [ "fingers", "butterfly", "hands", "open" ],
+    "char": "\ud83d\udc50",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  muscle: {
+    keywords: [ "arm", "flex", "hand", "summer", "strong", "biceps" ],
+    "char": "\ud83d\udcaa",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pray: {
+    keywords: [ "please", "hope", "wish", "namaste", "highfive" ],
+    "char": "\ud83d\ude4f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  foot: {
+    keywords: [ "kick", "stomp" ],
+    "char": "\ud83e\uddb6",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  leg: {
+    keywords: [ "kick", "limb" ],
+    "char": "\ud83e\uddb5",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  handshake: {
+    keywords: [ "agreement", "shake" ],
+    "char": "\ud83e\udd1d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  point_up: {
+    keywords: [ "hand", "fingers", "direction", "up" ],
+    "char": "\u261d",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_up_2: {
+    keywords: [ "fingers", "hand", "direction", "up" ],
+    "char": "\ud83d\udc46",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_down: {
+    keywords: [ "fingers", "hand", "direction", "down" ],
+    "char": "\ud83d\udc47",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_left: {
+    keywords: [ "direction", "fingers", "hand", "left" ],
+    "char": "\ud83d\udc48",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  point_right: {
+    keywords: [ "fingers", "hand", "direction", "right" ],
+    "char": "\ud83d\udc49",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  fu: {
+    keywords: [ "hand", "fingers", "rude", "middle", "flipping" ],
+    "char": "\ud83d\udd95",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raised_hand_with_fingers_splayed: {
+    keywords: [ "hand", "fingers", "palm" ],
+    "char": "\ud83d\udd90",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  love_you: {
+    keywords: [ "hand", "fingers", "gesture" ],
+    "char": "\ud83e\udd1f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  metal: {
+    keywords: [ "hand", "fingers", "evil_eye", "sign_of_horns", "rock_on" ],
+    "char": "\ud83e\udd18",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  crossed_fingers: {
+    keywords: [ "good", "lucky" ],
+    "char": "\ud83e\udd1e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  vulcan_salute: {
+    keywords: [ "hand", "fingers", "spock", "star trek" ],
+    "char": "\ud83d\udd96",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  writing_hand: {
+    keywords: [ "lower_left_ballpoint_pen", "stationery", "write", "compose" ],
+    "char": "\u270d",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  selfie: {
+    keywords: [ "camera", "phone" ],
+    "char": "\ud83e\udd33",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  nail_care: {
+    keywords: [ "beauty", "manicure", "finger", "fashion", "nail" ],
+    "char": "\ud83d\udc85",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  lips: {
+    keywords: [ "mouth", "kiss" ],
+    "char": "\ud83d\udc44",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tooth: {
+    keywords: [ "teeth", "dentist" ],
+    "char": "\ud83e\uddb7",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tongue: {
+    keywords: [ "mouth", "playful" ],
+    "char": "\ud83d\udc45",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ear: {
+    keywords: [ "face", "hear", "sound", "listen" ],
+    "char": "\ud83d\udc42",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  nose: {
+    keywords: [ "smell", "sniff" ],
+    "char": "\ud83d\udc43",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  eye: {
+    keywords: [ "face", "look", "see", "watch", "stare" ],
+    "char": "\ud83d\udc41",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  eyes: {
+    keywords: [ "look", "watch", "stalk", "peek", "see" ],
+    "char": "\ud83d\udc40",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  brain: {
+    keywords: [ "smart", "intelligent" ],
+    "char": "\ud83e\udde0",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bust_in_silhouette: {
+    keywords: [ "user", "person", "human" ],
+    "char": "\ud83d\udc64",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  busts_in_silhouette: {
+    keywords: [ "user", "person", "human", "group", "team" ],
+    "char": "\ud83d\udc65",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  speaking_head: {
+    keywords: [ "user", "person", "human", "sing", "say", "talk" ],
+    "char": "\ud83d\udde3",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  baby: {
+    keywords: [ "child", "boy", "girl", "toddler" ],
+    "char": "\ud83d\udc76",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  child: {
+    keywords: [ "gender-neutral", "young" ],
+    "char": "\ud83e\uddd2",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  boy: {
+    keywords: [ "man", "male", "guy", "teenager" ],
+    "char": "\ud83d\udc66",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  girl: {
+    keywords: [ "female", "woman", "teenager" ],
+    "char": "\ud83d\udc67",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  adult: {
+    keywords: [ "gender-neutral", "person" ],
+    "char": "\ud83e\uddd1",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man: {
+    keywords: [ "mustache", "father", "dad", "guy", "classy", "sir", "moustache" ],
+    "char": "\ud83d\udc68",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman: {
+    keywords: [ "female", "girls", "lady" ],
+    "char": "\ud83d\udc69",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  blonde_woman: {
+    keywords: [ "woman", "female", "girl", "blonde", "person" ],
+    "char": "\ud83d\udc71\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  blonde_man: {
+    keywords: [ "man", "male", "boy", "blonde", "guy", "person" ],
+    "char": "\ud83d\udc71",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bearded_person: {
+    keywords: [ "person", "bewhiskered" ],
+    "char": "\ud83e\uddd4",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_adult: {
+    keywords: [ "human", "elder", "senior", "gender-neutral" ],
+    "char": "\ud83e\uddd3",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_man: {
+    keywords: [ "human", "male", "men", "old", "elder", "senior" ],
+    "char": "\ud83d\udc74",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  older_woman: {
+    keywords: [ "human", "female", "women", "lady", "old", "elder", "senior" ],
+    "char": "\ud83d\udc75",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_with_gua_pi_mao: {
+    keywords: [ "male", "boy", "chinese" ],
+    "char": "\ud83d\udc72",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_with_headscarf: {
+    keywords: [ "female", "hijab", "mantilla", "tichel" ],
+    "char": "\ud83e\uddd5",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_with_turban: {
+    keywords: [ "female", "indian", "hinduism", "arabs", "woman" ],
+    "char": "\ud83d\udc73\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_with_turban: {
+    keywords: [ "male", "indian", "hinduism", "arabs" ],
+    "char": "\ud83d\udc73",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  policewoman: {
+    keywords: [ "woman", "police", "law", "legal", "enforcement", "arrest", "911", "female" ],
+    "char": "\ud83d\udc6e\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  policeman: {
+    keywords: [ "man", "police", "law", "legal", "enforcement", "arrest", "911" ],
+    "char": "\ud83d\udc6e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  construction_worker_woman: {
+    keywords: [ "female", "human", "wip", "build", "construction", "worker", "labor", "woman" ],
+    "char": "\ud83d\udc77\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  construction_worker_man: {
+    keywords: [ "male", "human", "wip", "guy", "build", "construction", "worker", "labor" ],
+    "char": "\ud83d\udc77",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  guardswoman: {
+    keywords: [ "uk", "gb", "british", "female", "royal", "woman" ],
+    "char": "\ud83d\udc82\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  guardsman: {
+    keywords: [ "uk", "gb", "british", "male", "guy", "royal" ],
+    "char": "\ud83d\udc82",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  female_detective: {
+    keywords: [ "human", "spy", "detective", "female", "woman" ],
+    "char": "\ud83d\udd75\ufe0f\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  male_detective: {
+    keywords: [ "human", "spy", "detective" ],
+    "char": "\ud83d\udd75",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_health_worker: {
+    keywords: [ "doctor", "nurse", "therapist", "healthcare", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\u2695\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_health_worker: {
+    keywords: [ "doctor", "nurse", "therapist", "healthcare", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\u2695\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_farmer: {
+    keywords: [ "rancher", "gardener", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udf3e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_farmer: {
+    keywords: [ "rancher", "gardener", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udf3e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_cook: {
+    keywords: [ "chef", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udf73",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_cook: {
+    keywords: [ "chef", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udf73",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_student: {
+    keywords: [ "graduate", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udf93",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_student: {
+    keywords: [ "graduate", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udf93",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_singer: {
+    keywords: [ "rockstar", "entertainer", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udfa4",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_singer: {
+    keywords: [ "rockstar", "entertainer", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udfa4",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_teacher: {
+    keywords: [ "instructor", "professor", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udfeb",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_teacher: {
+    keywords: [ "instructor", "professor", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udfeb",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_factory_worker: {
+    keywords: [ "assembly", "industrial", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udfed",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_factory_worker: {
+    keywords: [ "assembly", "industrial", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udfed",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_technologist: {
+    keywords: [ "coder", "developer", "engineer", "programmer", "software", "woman", "human", "laptop", "computer" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udcbb",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_technologist: {
+    keywords: [ "coder", "developer", "engineer", "programmer", "software", "man", "human", "laptop", "computer" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udcbb",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_office_worker: {
+    keywords: [ "business", "manager", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udcbc",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_office_worker: {
+    keywords: [ "business", "manager", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udcbc",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_mechanic: {
+    keywords: [ "plumber", "woman", "human", "wrench" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udd27",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_mechanic: {
+    keywords: [ "plumber", "man", "human", "wrench" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udd27",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_scientist: {
+    keywords: [ "biologist", "chemist", "engineer", "physicist", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udd2c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_scientist: {
+    keywords: [ "biologist", "chemist", "engineer", "physicist", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udd2c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_artist: {
+    keywords: [ "painter", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83c\udfa8",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_artist: {
+    keywords: [ "painter", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83c\udfa8",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_firefighter: {
+    keywords: [ "fireman", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83d\ude92",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_firefighter: {
+    keywords: [ "fireman", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83d\ude92",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_pilot: {
+    keywords: [ "aviator", "plane", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\u2708\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_pilot: {
+    keywords: [ "aviator", "plane", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\u2708\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_astronaut: {
+    keywords: [ "space", "rocket", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\ud83d\ude80",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_astronaut: {
+    keywords: [ "space", "rocket", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\ud83d\ude80",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_judge: {
+    keywords: [ "justice", "court", "woman", "human" ],
+    "char": "\ud83d\udc69\u200d\u2696\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_judge: {
+    keywords: [ "justice", "court", "man", "human" ],
+    "char": "\ud83d\udc68\u200d\u2696\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_superhero: {
+    keywords: [ "woman", "female", "good", "heroine", "superpowers" ],
+    "char": "\ud83e\uddb8\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_superhero: {
+    keywords: [ "man", "male", "good", "hero", "superpowers" ],
+    "char": "\ud83e\uddb8\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_supervillain: {
+    keywords: [ "woman", "female", "evil", "bad", "criminal", "heroine", "superpowers" ],
+    "char": "\ud83e\uddb9\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_supervillain: {
+    keywords: [ "man", "male", "evil", "bad", "criminal", "hero", "superpowers" ],
+    "char": "\ud83e\uddb9\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  mrs_claus: {
+    keywords: [ "woman", "female", "xmas", "mother christmas" ],
+    "char": "\ud83e\udd36",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  santa: {
+    keywords: [ "festival", "man", "male", "xmas", "father christmas" ],
+    "char": "\ud83c\udf85",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  sorceress: {
+    keywords: [ "woman", "female", "mage", "witch" ],
+    "char": "\ud83e\uddd9\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  wizard: {
+    keywords: [ "man", "male", "mage", "sorcerer" ],
+    "char": "\ud83e\uddd9\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_elf: {
+    keywords: [ "woman", "female" ],
+    "char": "\ud83e\udddd\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_elf: {
+    keywords: [ "man", "male" ],
+    "char": "\ud83e\udddd\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_vampire: {
+    keywords: [ "woman", "female" ],
+    "char": "\ud83e\udddb\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_vampire: {
+    keywords: [ "man", "male", "dracula" ],
+    "char": "\ud83e\udddb\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_zombie: {
+    keywords: [ "woman", "female", "undead", "walking dead" ],
+    "char": "\ud83e\udddf\u200d\u2640\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  man_zombie: {
+    keywords: [ "man", "male", "dracula", "undead", "walking dead" ],
+    "char": "\ud83e\udddf\u200d\u2642\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  woman_genie: {
+    keywords: [ "woman", "female" ],
+    "char": "\ud83e\uddde\u200d\u2640\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  man_genie: {
+    keywords: [ "man", "male" ],
+    "char": "\ud83e\uddde\u200d\u2642\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mermaid: {
+    keywords: [ "woman", "female", "merwoman", "ariel" ],
+    "char": "\ud83e\udddc\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  merman: {
+    keywords: [ "man", "male", "triton" ],
+    "char": "\ud83e\udddc\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_fairy: {
+    keywords: [ "woman", "female" ],
+    "char": "\ud83e\uddda\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_fairy: {
+    keywords: [ "man", "male" ],
+    "char": "\ud83e\uddda\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  angel: {
+    keywords: [ "heaven", "wings", "halo" ],
+    "char": "\ud83d\udc7c",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pregnant_woman: {
+    keywords: [ "baby" ],
+    "char": "\ud83e\udd30",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  breastfeeding: {
+    keywords: [ "nursing", "baby" ],
+    "char": "\ud83e\udd31",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  princess: {
+    keywords: [ "girl", "woman", "female", "blond", "crown", "royal", "queen" ],
+    "char": "\ud83d\udc78",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  prince: {
+    keywords: [ "boy", "man", "male", "crown", "royal", "king" ],
+    "char": "\ud83e\udd34",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bride_with_veil: {
+    keywords: [ "couple", "marriage", "wedding", "woman", "bride" ],
+    "char": "\ud83d\udc70",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_in_tuxedo: {
+    keywords: [ "couple", "marriage", "wedding", "groom" ],
+    "char": "\ud83e\udd35",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  running_woman: {
+    keywords: [ "woman", "walking", "exercise", "race", "running", "female" ],
+    "char": "\ud83c\udfc3\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  running_man: {
+    keywords: [ "man", "walking", "exercise", "race", "running" ],
+    "char": "\ud83c\udfc3",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  walking_woman: {
+    keywords: [ "human", "feet", "steps", "woman", "female" ],
+    "char": "\ud83d\udeb6\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  walking_man: {
+    keywords: [ "human", "feet", "steps" ],
+    "char": "\ud83d\udeb6",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  dancer: {
+    keywords: [ "female", "girl", "woman", "fun" ],
+    "char": "\ud83d\udc83",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_dancing: {
+    keywords: [ "male", "boy", "fun", "dancer" ],
+    "char": "\ud83d\udd7a",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  dancing_women: {
+    keywords: [ "female", "bunny", "women", "girls" ],
+    "char": "\ud83d\udc6f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dancing_men: {
+    keywords: [ "male", "bunny", "men", "boys" ],
+    "char": "\ud83d\udc6f\u200d\u2642\ufe0f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple: {
+    keywords: [ "pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage" ],
+    "char": "\ud83d\udc6b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  two_men_holding_hands: {
+    keywords: [ "pair", "couple", "love", "like", "bromance", "friendship", "people", "human" ],
+    "char": "\ud83d\udc6c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  two_women_holding_hands: {
+    keywords: [ "pair", "friendship", "couple", "love", "like", "female", "people", "human" ],
+    "char": "\ud83d\udc6d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bowing_woman: {
+    keywords: [ "woman", "female", "girl" ],
+    "char": "\ud83d\ude47\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  bowing_man: {
+    keywords: [ "man", "male", "boy" ],
+    "char": "\ud83d\ude47",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_facepalming: {
+    keywords: [ "man", "male", "boy", "disbelief" ],
+    "char": "\ud83e\udd26\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_facepalming: {
+    keywords: [ "woman", "female", "girl", "disbelief" ],
+    "char": "\ud83e\udd26\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_shrugging: {
+    keywords: [ "woman", "female", "girl", "confused", "indifferent", "doubt" ],
+    "char": "\ud83e\udd37",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_shrugging: {
+    keywords: [ "man", "male", "boy", "confused", "indifferent", "doubt" ],
+    "char": "\ud83e\udd37\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  tipping_hand_woman: {
+    keywords: [ "female", "girl", "woman", "human", "information" ],
+    "char": "\ud83d\udc81",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  tipping_hand_man: {
+    keywords: [ "male", "boy", "man", "human", "information" ],
+    "char": "\ud83d\udc81\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  no_good_woman: {
+    keywords: [ "female", "girl", "woman", "nope" ],
+    "char": "\ud83d\ude45",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  no_good_man: {
+    keywords: [ "male", "boy", "man", "nope" ],
+    "char": "\ud83d\ude45\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_woman: {
+    keywords: [ "women", "girl", "female", "pink", "human", "woman" ],
+    "char": "\ud83d\ude46",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  ok_man: {
+    keywords: [ "men", "boy", "male", "blue", "human", "man" ],
+    "char": "\ud83d\ude46\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raising_hand_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": "\ud83d\ude4b",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  raising_hand_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": "\ud83d\ude4b\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pouting_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": "\ud83d\ude4e",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  pouting_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": "\ud83d\ude4e\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  frowning_woman: {
+    keywords: [ "female", "girl", "woman", "sad", "depressed", "discouraged", "unhappy" ],
+    "char": "\ud83d\ude4d",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  frowning_man: {
+    keywords: [ "male", "boy", "man", "sad", "depressed", "discouraged", "unhappy" ],
+    "char": "\ud83d\ude4d\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  haircut_woman: {
+    keywords: [ "female", "girl", "woman" ],
+    "char": "\ud83d\udc87",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  haircut_man: {
+    keywords: [ "male", "boy", "man" ],
+    "char": "\ud83d\udc87\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  massage_woman: {
+    keywords: [ "female", "girl", "woman", "head" ],
+    "char": "\ud83d\udc86",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  massage_man: {
+    keywords: [ "male", "boy", "man", "head" ],
+    "char": "\ud83d\udc86\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  woman_in_steamy_room: {
+    keywords: [ "female", "woman", "spa", "steamroom", "sauna" ],
+    "char": "\ud83e\uddd6\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  man_in_steamy_room: {
+    keywords: [ "male", "man", "spa", "steamroom", "sauna" ],
+    "char": "\ud83e\uddd6\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "people"
+  },
+  couple_with_heart_woman_man: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": "\ud83d\udc91",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple_with_heart_woman_woman: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": "\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc69",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couple_with_heart_man_man: {
+    keywords: [ "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage" ],
+    "char": "\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_man_woman: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": "\ud83d\udc8f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_woman_woman: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": "\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  couplekiss_man_man: {
+    keywords: [ "pair", "valentines", "love", "like", "dating", "marriage" ],
+    "char": "\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_boy: {
+    keywords: [ "home", "parents", "child", "mom", "dad", "father", "mother", "people", "human" ],
+    "char": "\ud83d\udc6a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl: {
+    keywords: [ "home", "parents", "people", "human", "child" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_woman_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_woman_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_boy_boy: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_man_girl_girl: {
+    keywords: [ "home", "parents", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_boy: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_boy_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_woman_girl_girl: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_boy: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl: {
+    keywords: [ "home", "parent", "people", "human", "child" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_boy_boy: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  family_man_girl_girl: {
+    keywords: [ "home", "parent", "people", "human", "children" ],
+    "char": "\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  yarn: {
+    keywords: [ "ball", "crochet", "knit" ],
+    "char": "\ud83e\uddf6",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  thread: {
+    keywords: [ "needle", "sewing", "spool", "string" ],
+    "char": "\ud83e\uddf5",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  coat: {
+    keywords: [ "jacket" ],
+    "char": "\ud83e\udde5",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  labcoat: {
+    keywords: [ "doctor", "experiment", "scientist", "chemist" ],
+    "char": "\ud83e\udd7c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  womans_clothes: {
+    keywords: [ "fashion", "shopping_bags", "female" ],
+    "char": "\ud83d\udc5a",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tshirt: {
+    keywords: [ "fashion", "cloth", "casual", "shirt", "tee" ],
+    "char": "\ud83d\udc55",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  jeans: {
+    keywords: [ "fashion", "shopping" ],
+    "char": "\ud83d\udc56",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  necktie: {
+    keywords: [ "shirt", "suitup", "formal", "fashion", "cloth", "business" ],
+    "char": "\ud83d\udc54",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dress: {
+    keywords: [ "clothes", "fashion", "shopping" ],
+    "char": "\ud83d\udc57",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  bikini: {
+    keywords: [ "swimming", "female", "woman", "girl", "fashion", "beach", "summer" ],
+    "char": "\ud83d\udc59",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kimono: {
+    keywords: [ "dress", "fashion", "women", "female", "japanese" ],
+    "char": "\ud83d\udc58",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  lipstick: {
+    keywords: [ "female", "girl", "fashion", "woman" ],
+    "char": "\ud83d\udc84",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  kiss: {
+    keywords: [ "face", "lips", "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc8b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  footprints: {
+    keywords: [ "feet", "tracking", "walking", "beach" ],
+    "char": "\ud83d\udc63",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  flat_shoe: {
+    keywords: [ "ballet", "slip-on", "slipper" ],
+    "char": "\ud83e\udd7f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  high_heel: {
+    keywords: [ "fashion", "shoes", "female", "pumps", "stiletto" ],
+    "char": "\ud83d\udc60",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  sandal: {
+    keywords: [ "shoes", "fashion", "flip flops" ],
+    "char": "\ud83d\udc61",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  boot: {
+    keywords: [ "shoes", "fashion" ],
+    "char": "\ud83d\udc62",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mans_shoe: {
+    keywords: [ "fashion", "male" ],
+    "char": "\ud83d\udc5e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  athletic_shoe: {
+    keywords: [ "shoes", "sports", "sneakers" ],
+    "char": "\ud83d\udc5f",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  hiking_boot: {
+    keywords: [ "backpacking", "camping", "hiking" ],
+    "char": "\ud83e\udd7e",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  socks: {
+    keywords: [ "stockings", "clothes" ],
+    "char": "\ud83e\udde6",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  gloves: {
+    keywords: [ "hands", "winter", "clothes" ],
+    "char": "\ud83e\udde4",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  scarf: {
+    keywords: [ "neck", "winter", "clothes" ],
+    "char": "\ud83e\udde3",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  womans_hat: {
+    keywords: [ "fashion", "accessories", "female", "lady", "spring" ],
+    "char": "\ud83d\udc52",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  tophat: {
+    keywords: [ "magic", "gentleman", "classy", "circus" ],
+    "char": "\ud83c\udfa9",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  billed_hat: {
+    keywords: [ "cap", "baseball" ],
+    "char": "\ud83e\udde2",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  rescue_worker_helmet: {
+    keywords: [ "construction", "build" ],
+    "char": "\u26d1",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  mortar_board: {
+    keywords: [ "school", "college", "degree", "university", "graduation", "cap", "hat", "legal", "learn", "education" ],
+    "char": "\ud83c\udf93",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  crown: {
+    keywords: [ "king", "kod", "leader", "royalty", "lord" ],
+    "char": "\ud83d\udc51",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  school_satchel: {
+    keywords: [ "student", "education", "bag", "backpack" ],
+    "char": "\ud83c\udf92",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  luggage: {
+    keywords: [ "packing", "travel" ],
+    "char": "\ud83e\uddf3",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  pouch: {
+    keywords: [ "bag", "accessories", "shopping" ],
+    "char": "\ud83d\udc5d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  purse: {
+    keywords: [ "fashion", "accessories", "money", "sales", "shopping" ],
+    "char": "\ud83d\udc5b",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  handbag: {
+    keywords: [ "fashion", "accessory", "accessories", "shopping" ],
+    "char": "\ud83d\udc5c",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  briefcase: {
+    keywords: [ "business", "documents", "work", "law", "legal", "job", "career" ],
+    "char": "\ud83d\udcbc",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  eyeglasses: {
+    keywords: [ "fashion", "accessories", "eyesight", "nerdy", "dork", "geek" ],
+    "char": "\ud83d\udc53",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dark_sunglasses: {
+    keywords: [ "face", "cool", "accessories" ],
+    "char": "\ud83d\udd76",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  goggles: {
+    keywords: [ "eyes", "protection", "safety" ],
+    "char": "\ud83e\udd7d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  ring: {
+    keywords: [ "wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement" ],
+    "char": "\ud83d\udc8d",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  closed_umbrella: {
+    keywords: [ "weather", "rain", "drizzle" ],
+    "char": "\ud83c\udf02",
+    fitzpatrick_scale: false,
+    category: "people"
+  },
+  dog: {
+    keywords: [ "animal", "friend", "nature", "woof", "puppy", "pet", "faithful" ],
+    "char": "\ud83d\udc36",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cat: {
+    keywords: [ "animal", "meow", "nature", "pet", "kitten" ],
+    "char": "\ud83d\udc31",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mouse: {
+    keywords: [ "animal", "nature", "cheese_wedge", "rodent" ],
+    "char": "\ud83d\udc2d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hamster: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc39",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rabbit: {
+    keywords: [ "animal", "nature", "pet", "spring", "magic", "bunny" ],
+    "char": "\ud83d\udc30",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fox_face: {
+    keywords: [ "animal", "nature", "face" ],
+    "char": "\ud83e\udd8a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bear: {
+    keywords: [ "animal", "nature", "wild" ],
+    "char": "\ud83d\udc3b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  panda_face: {
+    keywords: [ "animal", "nature", "panda" ],
+    "char": "\ud83d\udc3c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  koala: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc28",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tiger: {
+    keywords: [ "animal", "cat", "danger", "wild", "nature", "roar" ],
+    "char": "\ud83d\udc2f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lion: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83e\udd81",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cow: {
+    keywords: [ "beef", "ox", "animal", "nature", "moo", "milk" ],
+    "char": "\ud83d\udc2e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig: {
+    keywords: [ "animal", "oink", "nature" ],
+    "char": "\ud83d\udc37",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig_nose: {
+    keywords: [ "animal", "oink" ],
+    "char": "\ud83d\udc3d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  frog: {
+    keywords: [ "animal", "nature", "croak", "toad" ],
+    "char": "\ud83d\udc38",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  squid: {
+    keywords: [ "animal", "nature", "ocean", "sea" ],
+    "char": "\ud83e\udd91",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  octopus: {
+    keywords: [ "animal", "creature", "ocean", "sea", "nature", "beach" ],
+    "char": "\ud83d\udc19",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shrimp: {
+    keywords: [ "animal", "ocean", "nature", "seafood" ],
+    "char": "\ud83e\udd90",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  monkey_face: {
+    keywords: [ "animal", "nature", "circus" ],
+    "char": "\ud83d\udc35",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  gorilla: {
+    keywords: [ "animal", "nature", "circus" ],
+    "char": "\ud83e\udd8d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  see_no_evil: {
+    keywords: [ "monkey", "animal", "nature", "haha" ],
+    "char": "\ud83d\ude48",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hear_no_evil: {
+    keywords: [ "animal", "monkey", "nature" ],
+    "char": "\ud83d\ude49",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  speak_no_evil: {
+    keywords: [ "monkey", "animal", "nature", "omg" ],
+    "char": "\ud83d\ude4a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  monkey: {
+    keywords: [ "animal", "nature", "banana", "circus" ],
+    "char": "\ud83d\udc12",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chicken: {
+    keywords: [ "animal", "cluck", "nature", "bird" ],
+    "char": "\ud83d\udc14",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  penguin: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc27",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bird: {
+    keywords: [ "animal", "nature", "fly", "tweet", "spring" ],
+    "char": "\ud83d\udc26",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  baby_chick: {
+    keywords: [ "animal", "chicken", "bird" ],
+    "char": "\ud83d\udc24",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hatching_chick: {
+    keywords: [ "animal", "chicken", "egg", "born", "baby", "bird" ],
+    "char": "\ud83d\udc23",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hatched_chick: {
+    keywords: [ "animal", "chicken", "baby", "bird" ],
+    "char": "\ud83d\udc25",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  duck: {
+    keywords: [ "animal", "nature", "bird", "mallard" ],
+    "char": "\ud83e\udd86",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  eagle: {
+    keywords: [ "animal", "nature", "bird" ],
+    "char": "\ud83e\udd85",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  owl: {
+    keywords: [ "animal", "nature", "bird", "hoot" ],
+    "char": "\ud83e\udd89",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bat: {
+    keywords: [ "animal", "nature", "blind", "vampire" ],
+    "char": "\ud83e\udd87",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wolf: {
+    keywords: [ "animal", "nature", "wild" ],
+    "char": "\ud83d\udc3a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  boar: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc17",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  horse: {
+    keywords: [ "animal", "brown", "nature" ],
+    "char": "\ud83d\udc34",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  unicorn: {
+    keywords: [ "animal", "nature", "mystical" ],
+    "char": "\ud83e\udd84",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  honeybee: {
+    keywords: [ "animal", "insect", "nature", "bug", "spring", "honey" ],
+    "char": "\ud83d\udc1d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bug: {
+    keywords: [ "animal", "insect", "nature", "worm" ],
+    "char": "\ud83d\udc1b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  butterfly: {
+    keywords: [ "animal", "insect", "nature", "caterpillar" ],
+    "char": "\ud83e\udd8b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snail: {
+    keywords: [ "slow", "animal", "shell" ],
+    "char": "\ud83d\udc0c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  beetle: {
+    keywords: [ "animal", "insect", "nature", "ladybug" ],
+    "char": "\ud83d\udc1e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ant: {
+    keywords: [ "animal", "insect", "nature", "bug" ],
+    "char": "\ud83d\udc1c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  grasshopper: {
+    keywords: [ "animal", "cricket", "chirp" ],
+    "char": "\ud83e\udd97",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  spider: {
+    keywords: [ "animal", "arachnid" ],
+    "char": "\ud83d\udd77",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  scorpion: {
+    keywords: [ "animal", "arachnid" ],
+    "char": "\ud83e\udd82",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crab: {
+    keywords: [ "animal", "crustacean" ],
+    "char": "\ud83e\udd80",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snake: {
+    keywords: [ "animal", "evil", "nature", "hiss", "python" ],
+    "char": "\ud83d\udc0d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lizard: {
+    keywords: [ "animal", "nature", "reptile" ],
+    "char": "\ud83e\udd8e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  "t-rex": {
+    keywords: [ "animal", "nature", "dinosaur", "tyrannosaurus", "extinct" ],
+    "char": "\ud83e\udd96",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sauropod: {
+    keywords: [ "animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct" ],
+    "char": "\ud83e\udd95",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  turtle: {
+    keywords: [ "animal", "slow", "nature", "tortoise" ],
+    "char": "\ud83d\udc22",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tropical_fish: {
+    keywords: [ "animal", "swim", "ocean", "beach", "nemo" ],
+    "char": "\ud83d\udc20",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fish: {
+    keywords: [ "animal", "food", "nature" ],
+    "char": "\ud83d\udc1f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  blowfish: {
+    keywords: [ "animal", "nature", "food", "sea", "ocean" ],
+    "char": "\ud83d\udc21",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dolphin: {
+    keywords: [ "animal", "nature", "fish", "sea", "ocean", "flipper", "fins", "beach" ],
+    "char": "\ud83d\udc2c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shark: {
+    keywords: [ "animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach" ],
+    "char": "\ud83e\udd88",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  whale: {
+    keywords: [ "animal", "nature", "sea", "ocean" ],
+    "char": "\ud83d\udc33",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  whale2: {
+    keywords: [ "animal", "nature", "sea", "ocean" ],
+    "char": "\ud83d\udc0b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crocodile: {
+    keywords: [ "animal", "nature", "reptile", "lizard", "alligator" ],
+    "char": "\ud83d\udc0a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  leopard: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc06",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  zebra: {
+    keywords: [ "animal", "nature", "stripes", "safari" ],
+    "char": "\ud83e\udd93",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tiger2: {
+    keywords: [ "animal", "nature", "roar" ],
+    "char": "\ud83d\udc05",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  water_buffalo: {
+    keywords: [ "animal", "nature", "ox", "cow" ],
+    "char": "\ud83d\udc03",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ox: {
+    keywords: [ "animal", "cow", "beef" ],
+    "char": "\ud83d\udc02",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cow2: {
+    keywords: [ "beef", "ox", "animal", "nature", "moo", "milk" ],
+    "char": "\ud83d\udc04",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  deer: {
+    keywords: [ "animal", "nature", "horns", "venison" ],
+    "char": "\ud83e\udd8c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dromedary_camel: {
+    keywords: [ "animal", "hot", "desert", "hump" ],
+    "char": "\ud83d\udc2a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  camel: {
+    keywords: [ "animal", "nature", "hot", "desert", "hump" ],
+    "char": "\ud83d\udc2b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  giraffe: {
+    keywords: [ "animal", "nature", "spots", "safari" ],
+    "char": "\ud83e\udd92",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  elephant: {
+    keywords: [ "animal", "nature", "nose", "th", "circus" ],
+    "char": "\ud83d\udc18",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rhinoceros: {
+    keywords: [ "animal", "nature", "horn" ],
+    "char": "\ud83e\udd8f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  goat: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc10",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ram: {
+    keywords: [ "animal", "sheep", "nature" ],
+    "char": "\ud83d\udc0f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sheep: {
+    keywords: [ "animal", "nature", "wool", "shipit" ],
+    "char": "\ud83d\udc11",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  racehorse: {
+    keywords: [ "animal", "gamble", "luck" ],
+    "char": "\ud83d\udc0e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  pig2: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83d\udc16",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rat: {
+    keywords: [ "animal", "mouse", "rodent" ],
+    "char": "\ud83d\udc00",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mouse2: {
+    keywords: [ "animal", "nature", "rodent" ],
+    "char": "\ud83d\udc01",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rooster: {
+    keywords: [ "animal", "nature", "chicken" ],
+    "char": "\ud83d\udc13",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  turkey: {
+    keywords: [ "animal", "bird" ],
+    "char": "\ud83e\udd83",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dove: {
+    keywords: [ "animal", "bird" ],
+    "char": "\ud83d\udd4a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dog2: {
+    keywords: [ "animal", "nature", "friend", "doge", "pet", "faithful" ],
+    "char": "\ud83d\udc15",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  poodle: {
+    keywords: [ "dog", "animal", "101", "nature", "pet" ],
+    "char": "\ud83d\udc29",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cat2: {
+    keywords: [ "animal", "meow", "pet", "cats" ],
+    "char": "\ud83d\udc08",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rabbit2: {
+    keywords: [ "animal", "nature", "pet", "magic", "spring" ],
+    "char": "\ud83d\udc07",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chipmunk: {
+    keywords: [ "animal", "nature", "rodent", "squirrel" ],
+    "char": "\ud83d\udc3f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hedgehog: {
+    keywords: [ "animal", "nature", "spiny" ],
+    "char": "\ud83e\udd94",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  raccoon: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83e\udd9d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  llama: {
+    keywords: [ "animal", "nature", "alpaca" ],
+    "char": "\ud83e\udd99",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hippopotamus: {
+    keywords: [ "animal", "nature" ],
+    "char": "\ud83e\udd9b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  kangaroo: {
+    keywords: [ "animal", "nature", "australia", "joey", "hop", "marsupial" ],
+    "char": "\ud83e\udd98",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  badger: {
+    keywords: [ "animal", "nature", "honey" ],
+    "char": "\ud83e\udda1",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  swan: {
+    keywords: [ "animal", "nature", "bird" ],
+    "char": "\ud83e\udda2",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  peacock: {
+    keywords: [ "animal", "nature", "peahen", "bird" ],
+    "char": "\ud83e\udd9a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  parrot: {
+    keywords: [ "animal", "nature", "bird", "pirate", "talk" ],
+    "char": "\ud83e\udd9c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  lobster: {
+    keywords: [ "animal", "nature", "bisque", "claws", "seafood" ],
+    "char": "\ud83e\udd9e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mosquito: {
+    keywords: [ "animal", "nature", "insect", "malaria" ],
+    "char": "\ud83e\udd9f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  paw_prints: {
+    keywords: [ "animal", "tracking", "footprints", "dog", "cat", "pet", "feet" ],
+    "char": "\ud83d\udc3e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dragon: {
+    keywords: [ "animal", "myth", "nature", "chinese", "green" ],
+    "char": "\ud83d\udc09",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dragon_face: {
+    keywords: [ "animal", "myth", "nature", "chinese", "green" ],
+    "char": "\ud83d\udc32",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cactus: {
+    keywords: [ "vegetable", "plant", "nature" ],
+    "char": "\ud83c\udf35",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  christmas_tree: {
+    keywords: [ "festival", "vacation", "december", "xmas", "celebration" ],
+    "char": "\ud83c\udf84",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  evergreen_tree: {
+    keywords: [ "plant", "nature" ],
+    "char": "\ud83c\udf32",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  deciduous_tree: {
+    keywords: [ "plant", "nature" ],
+    "char": "\ud83c\udf33",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  palm_tree: {
+    keywords: [ "plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical" ],
+    "char": "\ud83c\udf34",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  seedling: {
+    keywords: [ "plant", "nature", "grass", "lawn", "spring" ],
+    "char": "\ud83c\udf31",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  herb: {
+    keywords: [ "vegetable", "plant", "medicine", "weed", "grass", "lawn" ],
+    "char": "\ud83c\udf3f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shamrock: {
+    keywords: [ "vegetable", "plant", "nature", "irish", "clover" ],
+    "char": "\u2618",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  four_leaf_clover: {
+    keywords: [ "vegetable", "plant", "nature", "lucky", "irish" ],
+    "char": "\ud83c\udf40",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bamboo: {
+    keywords: [ "plant", "nature", "vegetable", "panda", "pine_decoration" ],
+    "char": "\ud83c\udf8d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tanabata_tree: {
+    keywords: [ "plant", "nature", "branch", "summer" ],
+    "char": "\ud83c\udf8b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  leaves: {
+    keywords: [ "nature", "plant", "tree", "vegetable", "grass", "lawn", "spring" ],
+    "char": "\ud83c\udf43",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fallen_leaf: {
+    keywords: [ "nature", "plant", "vegetable", "leaves" ],
+    "char": "\ud83c\udf42",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  maple_leaf: {
+    keywords: [ "nature", "plant", "vegetable", "ca", "fall" ],
+    "char": "\ud83c\udf41",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ear_of_rice: {
+    keywords: [ "nature", "plant" ],
+    "char": "\ud83c\udf3e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  hibiscus: {
+    keywords: [ "plant", "vegetable", "flowers", "beach" ],
+    "char": "\ud83c\udf3a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sunflower: {
+    keywords: [ "nature", "plant", "fall" ],
+    "char": "\ud83c\udf3b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  rose: {
+    keywords: [ "flowers", "valentines", "love", "spring" ],
+    "char": "\ud83c\udf39",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wilted_flower: {
+    keywords: [ "plant", "nature", "flower" ],
+    "char": "\ud83e\udd40",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tulip: {
+    keywords: [ "flowers", "plant", "nature", "summer", "spring" ],
+    "char": "\ud83c\udf37",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  blossom: {
+    keywords: [ "nature", "flowers", "yellow" ],
+    "char": "\ud83c\udf3c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cherry_blossom: {
+    keywords: [ "nature", "plant", "spring", "flower" ],
+    "char": "\ud83c\udf38",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  bouquet: {
+    keywords: [ "flowers", "nature", "spring" ],
+    "char": "\ud83d\udc90",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  mushroom: {
+    keywords: [ "plant", "vegetable" ],
+    "char": "\ud83c\udf44",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  chestnut: {
+    keywords: [ "food", "squirrel" ],
+    "char": "\ud83c\udf30",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  jack_o_lantern: {
+    keywords: [ "halloween", "light", "pumpkin", "creepy", "fall" ],
+    "char": "\ud83c\udf83",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  shell: {
+    keywords: [ "nature", "sea", "beach" ],
+    "char": "\ud83d\udc1a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  spider_web: {
+    keywords: [ "animal", "insect", "arachnid", "silk" ],
+    "char": "\ud83d\udd78",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_americas: {
+    keywords: [ "globe", "world", "USA", "international" ],
+    "char": "\ud83c\udf0e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_africa: {
+    keywords: [ "globe", "world", "international" ],
+    "char": "\ud83c\udf0d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  earth_asia: {
+    keywords: [ "globe", "world", "east", "international" ],
+    "char": "\ud83c\udf0f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  full_moon: {
+    keywords: [ "nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf15",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waning_gibbous_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing_gibbous_moon" ],
+    "char": "\ud83c\udf16",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  last_quarter_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf17",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waning_crescent_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf18",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  new_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf11",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waxing_crescent_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf12",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  first_quarter_moon: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf13",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  waxing_gibbous_moon: {
+    keywords: [ "nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep" ],
+    "char": "\ud83c\udf14",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  new_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf1a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  full_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf1d",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  first_quarter_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf1b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  last_quarter_moon_with_face: {
+    keywords: [ "nature", "twilight", "planet", "space", "night", "evening", "sleep" ],
+    "char": "\ud83c\udf1c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_with_face: {
+    keywords: [ "nature", "morning", "sky" ],
+    "char": "\ud83c\udf1e",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  crescent_moon: {
+    keywords: [ "night", "sleep", "sky", "evening", "magic" ],
+    "char": "\ud83c\udf19",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  star: {
+    keywords: [ "night", "yellow" ],
+    "char": "\u2b50",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  star2: {
+    keywords: [ "night", "sparkle", "awesome", "good", "magic" ],
+    "char": "\ud83c\udf1f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dizzy: {
+    keywords: [ "star", "sparkle", "shoot", "magic" ],
+    "char": "\ud83d\udcab",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sparkles: {
+    keywords: [ "stars", "shine", "shiny", "cool", "awesome", "good", "magic" ],
+    "char": "\u2728",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  comet: {
+    keywords: [ "space" ],
+    "char": "\u2604",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sunny: {
+    keywords: [ "weather", "nature", "brightness", "summer", "beach", "spring" ],
+    "char": "\u2600\ufe0f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_small_cloud: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf24",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  partly_sunny: {
+    keywords: [ "weather", "nature", "cloudy", "morning", "fall", "spring" ],
+    "char": "\u26c5",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_large_cloud: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf25",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sun_behind_rain_cloud: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf26",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud: {
+    keywords: [ "weather", "sky" ],
+    "char": "\u2601\ufe0f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_rain: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf27",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_lightning_and_rain: {
+    keywords: [ "weather", "lightning" ],
+    "char": "\u26c8",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_lightning: {
+    keywords: [ "weather", "thunder" ],
+    "char": "\ud83c\udf29",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  zap: {
+    keywords: [ "thunder", "weather", "lightning bolt", "fast" ],
+    "char": "\u26a1",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fire: {
+    keywords: [ "hot", "cook", "flame" ],
+    "char": "\ud83d\udd25",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  boom: {
+    keywords: [ "bomb", "explode", "explosion", "collision", "blown" ],
+    "char": "\ud83d\udca5",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowflake: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas" ],
+    "char": "\u2744\ufe0f",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  cloud_with_snow: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf28",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowman: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas", "frozen", "without_snow" ],
+    "char": "\u26c4",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  snowman_with_snow: {
+    keywords: [ "winter", "season", "cold", "weather", "christmas", "xmas", "frozen" ],
+    "char": "\u2603",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  wind_face: {
+    keywords: [ "gust", "air" ],
+    "char": "\ud83c\udf2c",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  dash: {
+    keywords: [ "wind", "air", "fast", "shoo", "fart", "smoke", "puff" ],
+    "char": "\ud83d\udca8",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  tornado: {
+    keywords: [ "weather", "cyclone", "twister" ],
+    "char": "\ud83c\udf2a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  fog: {
+    keywords: [ "weather" ],
+    "char": "\ud83c\udf2b",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  open_umbrella: {
+    keywords: [ "weather", "spring" ],
+    "char": "\u2602",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  umbrella: {
+    keywords: [ "rainy", "weather", "spring" ],
+    "char": "\u2614",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  droplet: {
+    keywords: [ "water", "drip", "faucet", "spring" ],
+    "char": "\ud83d\udca7",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  sweat_drops: {
+    keywords: [ "water", "drip", "oops" ],
+    "char": "\ud83d\udca6",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  ocean: {
+    keywords: [ "sea", "water", "wave", "nature", "tsunami", "disaster" ],
+    "char": "\ud83c\udf0a",
+    fitzpatrick_scale: false,
+    category: "animals_and_nature"
+  },
+  green_apple: {
+    keywords: [ "fruit", "nature" ],
+    "char": "\ud83c\udf4f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  apple: {
+    keywords: [ "fruit", "mac", "school" ],
+    "char": "\ud83c\udf4e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pear: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": "\ud83c\udf50",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tangerine: {
+    keywords: [ "food", "fruit", "nature", "orange" ],
+    "char": "\ud83c\udf4a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  lemon: {
+    keywords: [ "fruit", "nature" ],
+    "char": "\ud83c\udf4b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  banana: {
+    keywords: [ "fruit", "food", "monkey" ],
+    "char": "\ud83c\udf4c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  watermelon: {
+    keywords: [ "fruit", "food", "picnic", "summer" ],
+    "char": "\ud83c\udf49",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  grapes: {
+    keywords: [ "fruit", "food", "wine" ],
+    "char": "\ud83c\udf47",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  strawberry: {
+    keywords: [ "fruit", "food", "nature" ],
+    "char": "\ud83c\udf53",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  melon: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": "\ud83c\udf48",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cherries: {
+    keywords: [ "food", "fruit" ],
+    "char": "\ud83c\udf52",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  peach: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": "\ud83c\udf51",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pineapple: {
+    keywords: [ "fruit", "nature", "food" ],
+    "char": "\ud83c\udf4d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  coconut: {
+    keywords: [ "fruit", "nature", "food", "palm" ],
+    "char": "\ud83e\udd65",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  kiwi_fruit: {
+    keywords: [ "fruit", "food" ],
+    "char": "\ud83e\udd5d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  mango: {
+    keywords: [ "fruit", "food", "tropical" ],
+    "char": "\ud83e\udd6d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  avocado: {
+    keywords: [ "fruit", "food" ],
+    "char": "\ud83e\udd51",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  broccoli: {
+    keywords: [ "fruit", "food", "vegetable" ],
+    "char": "\ud83e\udd66",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tomato: {
+    keywords: [ "fruit", "vegetable", "nature", "food" ],
+    "char": "\ud83c\udf45",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  eggplant: {
+    keywords: [ "vegetable", "nature", "food", "aubergine" ],
+    "char": "\ud83c\udf46",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cucumber: {
+    keywords: [ "fruit", "food", "pickle" ],
+    "char": "\ud83e\udd52",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  carrot: {
+    keywords: [ "vegetable", "food", "orange" ],
+    "char": "\ud83e\udd55",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hot_pepper: {
+    keywords: [ "food", "spicy", "chilli", "chili" ],
+    "char": "\ud83c\udf36",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  potato: {
+    keywords: [ "food", "tuber", "vegatable", "starch" ],
+    "char": "\ud83e\udd54",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  corn: {
+    keywords: [ "food", "vegetable", "plant" ],
+    "char": "\ud83c\udf3d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  leafy_greens: {
+    keywords: [ "food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce" ],
+    "char": "\ud83e\udd6c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sweet_potato: {
+    keywords: [ "food", "nature" ],
+    "char": "\ud83c\udf60",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  peanuts: {
+    keywords: [ "food", "nut" ],
+    "char": "\ud83e\udd5c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  honey_pot: {
+    keywords: [ "bees", "sweet", "kitchen" ],
+    "char": "\ud83c\udf6f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  croissant: {
+    keywords: [ "food", "bread", "french" ],
+    "char": "\ud83e\udd50",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bread: {
+    keywords: [ "food", "wheat", "breakfast", "toast" ],
+    "char": "\ud83c\udf5e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  baguette_bread: {
+    keywords: [ "food", "bread", "french" ],
+    "char": "\ud83e\udd56",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bagel: {
+    keywords: [ "food", "bread", "bakery", "schmear" ],
+    "char": "\ud83e\udd6f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pretzel: {
+    keywords: [ "food", "bread", "twisted" ],
+    "char": "\ud83e\udd68",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cheese: {
+    keywords: [ "food", "chadder" ],
+    "char": "\ud83e\uddc0",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  egg: {
+    keywords: [ "food", "chicken", "breakfast" ],
+    "char": "\ud83e\udd5a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bacon: {
+    keywords: [ "food", "breakfast", "pork", "pig", "meat" ],
+    "char": "\ud83e\udd53",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  steak: {
+    keywords: [ "food", "cow", "meat", "cut", "chop", "lambchop", "porkchop" ],
+    "char": "\ud83e\udd69",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pancakes: {
+    keywords: [ "food", "breakfast", "flapjacks", "hotcakes" ],
+    "char": "\ud83e\udd5e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  poultry_leg: {
+    keywords: [ "food", "meat", "drumstick", "bird", "chicken", "turkey" ],
+    "char": "\ud83c\udf57",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  meat_on_bone: {
+    keywords: [ "good", "food", "drumstick" ],
+    "char": "\ud83c\udf56",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bone: {
+    keywords: [ "skeleton" ],
+    "char": "\ud83e\uddb4",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fried_shrimp: {
+    keywords: [ "food", "animal", "appetizer", "summer" ],
+    "char": "\ud83c\udf64",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fried_egg: {
+    keywords: [ "food", "breakfast", "kitchen", "egg" ],
+    "char": "\ud83c\udf73",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hamburger: {
+    keywords: [ "meat", "fast food", "beef", "cheeseburger", "mcdonalds", "burger king" ],
+    "char": "\ud83c\udf54",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fries: {
+    keywords: [ "chips", "snack", "fast food" ],
+    "char": "\ud83c\udf5f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  stuffed_flatbread: {
+    keywords: [ "food", "flatbread", "stuffed", "gyro" ],
+    "char": "\ud83e\udd59",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  hotdog: {
+    keywords: [ "food", "frankfurter" ],
+    "char": "\ud83c\udf2d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pizza: {
+    keywords: [ "food", "party" ],
+    "char": "\ud83c\udf55",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sandwich: {
+    keywords: [ "food", "lunch", "bread" ],
+    "char": "\ud83e\udd6a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  canned_food: {
+    keywords: [ "food", "soup" ],
+    "char": "\ud83e\udd6b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  spaghetti: {
+    keywords: [ "food", "italian", "noodle" ],
+    "char": "\ud83c\udf5d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  taco: {
+    keywords: [ "food", "mexican" ],
+    "char": "\ud83c\udf2e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  burrito: {
+    keywords: [ "food", "mexican" ],
+    "char": "\ud83c\udf2f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  green_salad: {
+    keywords: [ "food", "healthy", "lettuce" ],
+    "char": "\ud83e\udd57",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  shallow_pan_of_food: {
+    keywords: [ "food", "cooking", "casserole", "paella" ],
+    "char": "\ud83e\udd58",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  ramen: {
+    keywords: [ "food", "japanese", "noodle", "chopsticks" ],
+    "char": "\ud83c\udf5c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  stew: {
+    keywords: [ "food", "meat", "soup" ],
+    "char": "\ud83c\udf72",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fish_cake: {
+    keywords: [ "food", "japan", "sea", "beach", "narutomaki", "pink", "swirl", "kamaboko", "surimi", "ramen" ],
+    "char": "\ud83c\udf65",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fortune_cookie: {
+    keywords: [ "food", "prophecy" ],
+    "char": "\ud83e\udd60",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sushi: {
+    keywords: [ "food", "fish", "japanese", "rice" ],
+    "char": "\ud83c\udf63",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bento: {
+    keywords: [ "food", "japanese", "box" ],
+    "char": "\ud83c\udf71",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  curry: {
+    keywords: [ "food", "spicy", "hot", "indian" ],
+    "char": "\ud83c\udf5b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice_ball: {
+    keywords: [ "food", "japanese" ],
+    "char": "\ud83c\udf59",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice: {
+    keywords: [ "food", "china", "asian" ],
+    "char": "\ud83c\udf5a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  rice_cracker: {
+    keywords: [ "food", "japanese" ],
+    "char": "\ud83c\udf58",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  oden: {
+    keywords: [ "food", "japanese" ],
+    "char": "\ud83c\udf62",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  dango: {
+    keywords: [ "food", "dessert", "sweet", "japanese", "barbecue", "meat" ],
+    "char": "\ud83c\udf61",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  shaved_ice: {
+    keywords: [ "hot", "dessert", "summer" ],
+    "char": "\ud83c\udf67",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  ice_cream: {
+    keywords: [ "food", "hot", "dessert" ],
+    "char": "\ud83c\udf68",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  icecream: {
+    keywords: [ "food", "hot", "dessert", "summer" ],
+    "char": "\ud83c\udf66",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  pie: {
+    keywords: [ "food", "dessert", "pastry" ],
+    "char": "\ud83e\udd67",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cake: {
+    keywords: [ "food", "dessert" ],
+    "char": "\ud83c\udf70",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cupcake: {
+    keywords: [ "food", "dessert", "bakery", "sweet" ],
+    "char": "\ud83e\uddc1",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  moon_cake: {
+    keywords: [ "food", "autumn" ],
+    "char": "\ud83e\udd6e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  birthday: {
+    keywords: [ "food", "dessert", "cake" ],
+    "char": "\ud83c\udf82",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  custard: {
+    keywords: [ "dessert", "food" ],
+    "char": "\ud83c\udf6e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  candy: {
+    keywords: [ "snack", "dessert", "sweet", "lolly" ],
+    "char": "\ud83c\udf6c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  lollipop: {
+    keywords: [ "food", "snack", "candy", "sweet" ],
+    "char": "\ud83c\udf6d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  chocolate_bar: {
+    keywords: [ "food", "snack", "dessert", "sweet" ],
+    "char": "\ud83c\udf6b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  popcorn: {
+    keywords: [ "food", "movie theater", "films", "snack" ],
+    "char": "\ud83c\udf7f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  dumpling: {
+    keywords: [ "food", "empanada", "pierogi", "potsticker" ],
+    "char": "\ud83e\udd5f",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  doughnut: {
+    keywords: [ "food", "dessert", "snack", "sweet", "donut" ],
+    "char": "\ud83c\udf69",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cookie: {
+    keywords: [ "food", "snack", "oreo", "chocolate", "sweet", "dessert" ],
+    "char": "\ud83c\udf6a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  milk_glass: {
+    keywords: [ "beverage", "drink", "cow" ],
+    "char": "\ud83e\udd5b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  beer: {
+    keywords: [ "relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze" ],
+    "char": "\ud83c\udf7a",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  beers: {
+    keywords: [ "relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze" ],
+    "char": "\ud83c\udf7b",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  clinking_glasses: {
+    keywords: [ "beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast" ],
+    "char": "\ud83e\udd42",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  wine_glass: {
+    keywords: [ "drink", "beverage", "drunk", "alcohol", "booze" ],
+    "char": "\ud83c\udf77",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tumbler_glass: {
+    keywords: [ "drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "glass", "shot" ],
+    "char": "\ud83e\udd43",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cocktail: {
+    keywords: [ "drink", "drunk", "alcohol", "beverage", "booze", "mojito" ],
+    "char": "\ud83c\udf78",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tropical_drink: {
+    keywords: [ "beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito" ],
+    "char": "\ud83c\udf79",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  champagne: {
+    keywords: [ "drink", "wine", "bottle", "celebration" ],
+    "char": "\ud83c\udf7e",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  sake: {
+    keywords: [ "wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze" ],
+    "char": "\ud83c\udf76",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  tea: {
+    keywords: [ "drink", "bowl", "breakfast", "green", "british" ],
+    "char": "\ud83c\udf75",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  cup_with_straw: {
+    keywords: [ "drink", "soda" ],
+    "char": "\ud83e\udd64",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  coffee: {
+    keywords: [ "beverage", "caffeine", "latte", "espresso" ],
+    "char": "\u2615",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  baby_bottle: {
+    keywords: [ "food", "container", "milk" ],
+    "char": "\ud83c\udf7c",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  salt: {
+    keywords: [ "condiment", "shaker" ],
+    "char": "\ud83e\uddc2",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  spoon: {
+    keywords: [ "cutlery", "kitchen", "tableware" ],
+    "char": "\ud83e\udd44",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  fork_and_knife: {
+    keywords: [ "cutlery", "kitchen" ],
+    "char": "\ud83c\udf74",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  plate_with_cutlery: {
+    keywords: [ "food", "eat", "meal", "lunch", "dinner", "restaurant" ],
+    "char": "\ud83c\udf7d",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  bowl_with_spoon: {
+    keywords: [ "food", "breakfast", "cereal", "oatmeal", "porridge" ],
+    "char": "\ud83e\udd63",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  takeout_box: {
+    keywords: [ "food", "leftovers" ],
+    "char": "\ud83e\udd61",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  chopsticks: {
+    keywords: [ "food" ],
+    "char": "\ud83e\udd62",
+    fitzpatrick_scale: false,
+    category: "food_and_drink"
+  },
+  soccer: {
+    keywords: [ "sports", "football" ],
+    "char": "\u26bd",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  basketball: {
+    keywords: [ "sports", "balls", "NBA" ],
+    "char": "\ud83c\udfc0",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  football: {
+    keywords: [ "sports", "balls", "NFL" ],
+    "char": "\ud83c\udfc8",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  baseball: {
+    keywords: [ "sports", "balls" ],
+    "char": "\u26be",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  softball: {
+    keywords: [ "sports", "balls" ],
+    "char": "\ud83e\udd4e",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  tennis: {
+    keywords: [ "sports", "balls", "green" ],
+    "char": "\ud83c\udfbe",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  volleyball: {
+    keywords: [ "sports", "balls" ],
+    "char": "\ud83c\udfd0",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rugby_football: {
+    keywords: [ "sports", "team" ],
+    "char": "\ud83c\udfc9",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  flying_disc: {
+    keywords: [ "sports", "frisbee", "ultimate" ],
+    "char": "\ud83e\udd4f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "8ball": {
+    keywords: [ "pool", "hobby", "game", "luck", "magic" ],
+    "char": "\ud83c\udfb1",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golf: {
+    keywords: [ "sports", "business", "flag", "hole", "summer" ],
+    "char": "\u26f3",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golfing_woman: {
+    keywords: [ "sports", "business", "woman", "female" ],
+    "char": "\ud83c\udfcc\ufe0f\u200d\u2640\ufe0f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  golfing_man: {
+    keywords: [ "sports", "business" ],
+    "char": "\ud83c\udfcc",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  ping_pong: {
+    keywords: [ "sports", "pingpong" ],
+    "char": "\ud83c\udfd3",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  badminton: {
+    keywords: [ "sports" ],
+    "char": "\ud83c\udff8",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  goal_net: {
+    keywords: [ "sports" ],
+    "char": "\ud83e\udd45",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ice_hockey: {
+    keywords: [ "sports" ],
+    "char": "\ud83c\udfd2",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  field_hockey: {
+    keywords: [ "sports" ],
+    "char": "\ud83c\udfd1",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  lacrosse: {
+    keywords: [ "sports", "ball", "stick" ],
+    "char": "\ud83e\udd4d",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  cricket: {
+    keywords: [ "sports" ],
+    "char": "\ud83c\udfcf",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ski: {
+    keywords: [ "sports", "winter", "cold", "snow" ],
+    "char": "\ud83c\udfbf",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  skier: {
+    keywords: [ "sports", "winter", "snow" ],
+    "char": "\u26f7",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  snowboarder: {
+    keywords: [ "sports", "winter" ],
+    "char": "\ud83c\udfc2",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  person_fencing: {
+    keywords: [ "sports", "fencing", "sword" ],
+    "char": "\ud83e\udd3a",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  women_wrestling: {
+    keywords: [ "sports", "wrestlers" ],
+    "char": "\ud83e\udd3c\u200d\u2640\ufe0f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  men_wrestling: {
+    keywords: [ "sports", "wrestlers" ],
+    "char": "\ud83e\udd3c\u200d\u2642\ufe0f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  woman_cartwheeling: {
+    keywords: [ "gymnastics" ],
+    "char": "\ud83e\udd38\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_cartwheeling: {
+    keywords: [ "gymnastics" ],
+    "char": "\ud83e\udd38\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_playing_handball: {
+    keywords: [ "sports" ],
+    "char": "\ud83e\udd3e\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_playing_handball: {
+    keywords: [ "sports" ],
+    "char": "\ud83e\udd3e\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  ice_skate: {
+    keywords: [ "sports" ],
+    "char": "\u26f8",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  curling_stone: {
+    keywords: [ "sports" ],
+    "char": "\ud83e\udd4c",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  skateboard: {
+    keywords: [ "board" ],
+    "char": "\ud83d\udef9",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  sled: {
+    keywords: [ "sleigh", "luge", "toboggan" ],
+    "char": "\ud83d\udef7",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  bow_and_arrow: {
+    keywords: [ "sports" ],
+    "char": "\ud83c\udff9",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  fishing_pole_and_fish: {
+    keywords: [ "food", "hobby", "summer" ],
+    "char": "\ud83c\udfa3",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  boxing_glove: {
+    keywords: [ "sports", "fighting" ],
+    "char": "\ud83e\udd4a",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  martial_arts_uniform: {
+    keywords: [ "judo", "karate", "taekwondo" ],
+    "char": "\ud83e\udd4b",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rowing_woman: {
+    keywords: [ "sports", "hobby", "water", "ship", "woman", "female" ],
+    "char": "\ud83d\udea3\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  rowing_man: {
+    keywords: [ "sports", "hobby", "water", "ship" ],
+    "char": "\ud83d\udea3",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  climbing_woman: {
+    keywords: [ "sports", "hobby", "woman", "female", "rock" ],
+    "char": "\ud83e\uddd7\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  climbing_man: {
+    keywords: [ "sports", "hobby", "man", "male", "rock" ],
+    "char": "\ud83e\uddd7\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  swimming_woman: {
+    keywords: [ "sports", "exercise", "human", "athlete", "water", "summer", "woman", "female" ],
+    "char": "\ud83c\udfca\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  swimming_man: {
+    keywords: [ "sports", "exercise", "human", "athlete", "water", "summer" ],
+    "char": "\ud83c\udfca",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_playing_water_polo: {
+    keywords: [ "sports", "pool" ],
+    "char": "\ud83e\udd3d\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_playing_water_polo: {
+    keywords: [ "sports", "pool" ],
+    "char": "\ud83e\udd3d\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  woman_in_lotus_position: {
+    keywords: [ "woman", "female", "meditation", "yoga", "serenity", "zen", "mindfulness" ],
+    "char": "\ud83e\uddd8\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_in_lotus_position: {
+    keywords: [ "man", "male", "meditation", "yoga", "serenity", "zen", "mindfulness" ],
+    "char": "\ud83e\uddd8\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  surfing_woman: {
+    keywords: [ "sports", "ocean", "sea", "summer", "beach", "woman", "female" ],
+    "char": "\ud83c\udfc4\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  surfing_man: {
+    keywords: [ "sports", "ocean", "sea", "summer", "beach" ],
+    "char": "\ud83c\udfc4",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  bath: {
+    keywords: [ "clean", "shower", "bathroom" ],
+    "char": "\ud83d\udec0",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  basketball_woman: {
+    keywords: [ "sports", "human", "woman", "female" ],
+    "char": "\u26f9\ufe0f\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  basketball_man: {
+    keywords: [ "sports", "human" ],
+    "char": "\u26f9",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  weight_lifting_woman: {
+    keywords: [ "sports", "training", "exercise", "woman", "female" ],
+    "char": "\ud83c\udfcb\ufe0f\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  weight_lifting_man: {
+    keywords: [ "sports", "training", "exercise" ],
+    "char": "\ud83c\udfcb",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  biking_woman: {
+    keywords: [ "sports", "bike", "exercise", "hipster", "woman", "female" ],
+    "char": "\ud83d\udeb4\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  biking_man: {
+    keywords: [ "sports", "bike", "exercise", "hipster" ],
+    "char": "\ud83d\udeb4",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  mountain_biking_woman: {
+    keywords: [ "transportation", "sports", "human", "race", "bike", "woman", "female" ],
+    "char": "\ud83d\udeb5\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  mountain_biking_man: {
+    keywords: [ "transportation", "sports", "human", "race", "bike" ],
+    "char": "\ud83d\udeb5",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  horse_racing: {
+    keywords: [ "animal", "betting", "competition", "gambling", "luck" ],
+    "char": "\ud83c\udfc7",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  business_suit_levitating: {
+    keywords: [ "suit", "business", "levitate", "hover", "jump" ],
+    "char": "\ud83d\udd74",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  trophy: {
+    keywords: [ "win", "award", "contest", "place", "ftw", "ceremony" ],
+    "char": "\ud83c\udfc6",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  running_shirt_with_sash: {
+    keywords: [ "play", "pageant" ],
+    "char": "\ud83c\udfbd",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  medal_sports: {
+    keywords: [ "award", "winning" ],
+    "char": "\ud83c\udfc5",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  medal_military: {
+    keywords: [ "award", "winning", "army" ],
+    "char": "\ud83c\udf96",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "1st_place_medal": {
+    keywords: [ "award", "winning", "first" ],
+    "char": "\ud83e\udd47",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "2nd_place_medal": {
+    keywords: [ "award", "second" ],
+    "char": "\ud83e\udd48",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  "3rd_place_medal": {
+    keywords: [ "award", "third" ],
+    "char": "\ud83e\udd49",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  reminder_ribbon: {
+    keywords: [ "sports", "cause", "support", "awareness" ],
+    "char": "\ud83c\udf97",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  rosette: {
+    keywords: [ "flower", "decoration", "military" ],
+    "char": "\ud83c\udff5",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  ticket: {
+    keywords: [ "event", "concert", "pass" ],
+    "char": "\ud83c\udfab",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  tickets: {
+    keywords: [ "sports", "concert", "entrance" ],
+    "char": "\ud83c\udf9f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  performing_arts: {
+    keywords: [ "acting", "theater", "drama" ],
+    "char": "\ud83c\udfad",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  art: {
+    keywords: [ "design", "paint", "draw", "colors" ],
+    "char": "\ud83c\udfa8",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  circus_tent: {
+    keywords: [ "festival", "carnival", "party" ],
+    "char": "\ud83c\udfaa",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  woman_juggling: {
+    keywords: [ "juggle", "balance", "skill", "multitask" ],
+    "char": "\ud83e\udd39\u200d\u2640\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  man_juggling: {
+    keywords: [ "juggle", "balance", "skill", "multitask" ],
+    "char": "\ud83e\udd39\u200d\u2642\ufe0f",
+    fitzpatrick_scale: true,
+    category: "activity"
+  },
+  microphone: {
+    keywords: [ "sound", "music", "PA", "sing", "talkshow" ],
+    "char": "\ud83c\udfa4",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  headphones: {
+    keywords: [ "music", "score", "gadgets" ],
+    "char": "\ud83c\udfa7",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  musical_score: {
+    keywords: [ "treble", "clef", "compose" ],
+    "char": "\ud83c\udfbc",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  musical_keyboard: {
+    keywords: [ "piano", "instrument", "compose" ],
+    "char": "\ud83c\udfb9",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  drum: {
+    keywords: [ "music", "instrument", "drumsticks", "snare" ],
+    "char": "\ud83e\udd41",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  saxophone: {
+    keywords: [ "music", "instrument", "jazz", "blues" ],
+    "char": "\ud83c\udfb7",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  trumpet: {
+    keywords: [ "music", "brass" ],
+    "char": "\ud83c\udfba",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  guitar: {
+    keywords: [ "music", "instrument" ],
+    "char": "\ud83c\udfb8",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  violin: {
+    keywords: [ "music", "instrument", "orchestra", "symphony" ],
+    "char": "\ud83c\udfbb",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  clapper: {
+    keywords: [ "movie", "film", "record" ],
+    "char": "\ud83c\udfac",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  video_game: {
+    keywords: [ "play", "console", "PS4", "controller" ],
+    "char": "\ud83c\udfae",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  space_invader: {
+    keywords: [ "game", "arcade", "play" ],
+    "char": "\ud83d\udc7e",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  dart: {
+    keywords: [ "game", "play", "bar", "target", "bullseye" ],
+    "char": "\ud83c\udfaf",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  game_die: {
+    keywords: [ "dice", "random", "tabletop", "play", "luck" ],
+    "char": "\ud83c\udfb2",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  chess_pawn: {
+    keywords: [ "expendable" ],
+    "char": "\u265f",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  slot_machine: {
+    keywords: [ "bet", "gamble", "vegas", "fruit machine", "luck", "casino" ],
+    "char": "\ud83c\udfb0",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  jigsaw: {
+    keywords: [ "interlocking", "puzzle", "piece" ],
+    "char": "\ud83e\udde9",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  bowling: {
+    keywords: [ "sports", "fun", "play" ],
+    "char": "\ud83c\udfb3",
+    fitzpatrick_scale: false,
+    category: "activity"
+  },
+  red_car: {
+    keywords: [ "red", "transportation", "vehicle" ],
+    "char": "\ud83d\ude97",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  taxi: {
+    keywords: [ "uber", "vehicle", "cars", "transportation" ],
+    "char": "\ud83d\ude95",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  blue_car: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude99",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bus: {
+    keywords: [ "car", "vehicle", "transportation" ],
+    "char": "\ud83d\ude8c",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  trolleybus: {
+    keywords: [ "bart", "transportation", "vehicle" ],
+    "char": "\ud83d\ude8e",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  racing_car: {
+    keywords: [ "sports", "race", "fast", "formula", "f1" ],
+    "char": "\ud83c\udfce",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  police_car: {
+    keywords: [ "vehicle", "cars", "transportation", "law", "legal", "enforcement" ],
+    "char": "\ud83d\ude93",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ambulance: {
+    keywords: [ "health", "911", "hospital" ],
+    "char": "\ud83d\ude91",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fire_engine: {
+    keywords: [ "transportation", "cars", "vehicle" ],
+    "char": "\ud83d\ude92",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  minibus: {
+    keywords: [ "vehicle", "car", "transportation" ],
+    "char": "\ud83d\ude90",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  truck: {
+    keywords: [ "cars", "transportation" ],
+    "char": "\ud83d\ude9a",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  articulated_lorry: {
+    keywords: [ "vehicle", "cars", "transportation", "express" ],
+    "char": "\ud83d\ude9b",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tractor: {
+    keywords: [ "vehicle", "car", "farming", "agriculture" ],
+    "char": "\ud83d\ude9c",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  kick_scooter: {
+    keywords: [ "vehicle", "kick", "razor" ],
+    "char": "\ud83d\udef4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motorcycle: {
+    keywords: [ "race", "sports", "fast" ],
+    "char": "\ud83c\udfcd",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bike: {
+    keywords: [ "sports", "bicycle", "exercise", "hipster" ],
+    "char": "\ud83d\udeb2",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motor_scooter: {
+    keywords: [ "vehicle", "vespa", "sasha" ],
+    "char": "\ud83d\udef5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rotating_light: {
+    keywords: [ "police", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal" ],
+    "char": "\ud83d\udea8",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_police_car: {
+    keywords: [ "vehicle", "law", "legal", "enforcement", "911" ],
+    "char": "\ud83d\ude94",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_bus: {
+    keywords: [ "vehicle", "transportation" ],
+    "char": "\ud83d\ude8d",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_automobile: {
+    keywords: [ "car", "vehicle", "transportation" ],
+    "char": "\ud83d\ude98",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  oncoming_taxi: {
+    keywords: [ "vehicle", "cars", "uber" ],
+    "char": "\ud83d\ude96",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  aerial_tramway: {
+    keywords: [ "transportation", "vehicle", "ski" ],
+    "char": "\ud83d\udea1",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_cableway: {
+    keywords: [ "transportation", "vehicle", "ski" ],
+    "char": "\ud83d\udea0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  suspension_railway: {
+    keywords: [ "vehicle", "transportation" ],
+    "char": "\ud83d\ude9f",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  railway_car: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude83",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  train: {
+    keywords: [ "transportation", "vehicle", "carriage", "public", "travel" ],
+    "char": "\ud83d\ude8b",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  monorail: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude9d",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bullettrain_side: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude84",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bullettrain_front: {
+    keywords: [ "transportation", "vehicle", "speed", "fast", "public", "travel" ],
+    "char": "\ud83d\ude85",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  light_rail: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude88",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_railway: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude9e",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  steam_locomotive: {
+    keywords: [ "transportation", "vehicle", "train" ],
+    "char": "\ud83d\ude82",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  train2: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude86",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  metro: {
+    keywords: [ "transportation", "blue-square", "mrt", "underground", "tube" ],
+    "char": "\ud83d\ude87",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tram: {
+    keywords: [ "transportation", "vehicle" ],
+    "char": "\ud83d\ude8a",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  station: {
+    keywords: [ "transportation", "vehicle", "public" ],
+    "char": "\ud83d\ude89",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flying_saucer: {
+    keywords: [ "transportation", "vehicle", "ufo" ],
+    "char": "\ud83d\udef8",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  helicopter: {
+    keywords: [ "transportation", "vehicle", "fly" ],
+    "char": "\ud83d\ude81",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  small_airplane: {
+    keywords: [ "flight", "transportation", "fly", "vehicle" ],
+    "char": "\ud83d\udee9",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  airplane: {
+    keywords: [ "vehicle", "transportation", "flight", "fly" ],
+    "char": "\u2708\ufe0f",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flight_departure: {
+    keywords: [ "airport", "flight", "landing" ],
+    "char": "\ud83d\udeeb",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  flight_arrival: {
+    keywords: [ "airport", "flight", "boarding" ],
+    "char": "\ud83d\udeec",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sailboat: {
+    keywords: [ "ship", "summer", "transportation", "water", "sailing" ],
+    "char": "\u26f5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motor_boat: {
+    keywords: [ "ship" ],
+    "char": "\ud83d\udee5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  speedboat: {
+    keywords: [ "ship", "transportation", "vehicle", "summer" ],
+    "char": "\ud83d\udea4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ferry: {
+    keywords: [ "boat", "ship", "yacht" ],
+    "char": "\u26f4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  passenger_ship: {
+    keywords: [ "yacht", "cruise", "ferry" ],
+    "char": "\ud83d\udef3",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rocket: {
+    keywords: [ "launch", "ship", "staffmode", "NASA", "outer space", "outer_space", "fly" ],
+    "char": "\ud83d\ude80",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  artificial_satellite: {
+    keywords: [ "communication", "gps", "orbit", "spaceflight", "NASA", "ISS" ],
+    "char": "\ud83d\udef0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  seat: {
+    keywords: [ "sit", "airplane", "transport", "bus", "flight", "fly" ],
+    "char": "\ud83d\udcba",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  canoe: {
+    keywords: [ "boat", "paddle", "water", "ship" ],
+    "char": "\ud83d\udef6",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  anchor: {
+    keywords: [ "ship", "ferry", "sea", "boat" ],
+    "char": "\u2693",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  construction: {
+    keywords: [ "wip", "progress", "caution", "warning" ],
+    "char": "\ud83d\udea7",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fuelpump: {
+    keywords: [ "gas station", "petroleum" ],
+    "char": "\u26fd",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  busstop: {
+    keywords: [ "transportation", "wait" ],
+    "char": "\ud83d\ude8f",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  vertical_traffic_light: {
+    keywords: [ "transportation", "driving" ],
+    "char": "\ud83d\udea6",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  traffic_light: {
+    keywords: [ "transportation", "signal" ],
+    "char": "\ud83d\udea5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  checkered_flag: {
+    keywords: [ "contest", "finishline", "race", "gokart" ],
+    "char": "\ud83c\udfc1",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ship: {
+    keywords: [ "transportation", "titanic", "deploy" ],
+    "char": "\ud83d\udea2",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  ferris_wheel: {
+    keywords: [ "photo", "carnival", "londoneye" ],
+    "char": "\ud83c\udfa1",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  roller_coaster: {
+    keywords: [ "carnival", "playground", "photo", "fun" ],
+    "char": "\ud83c\udfa2",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  carousel_horse: {
+    keywords: [ "photo", "carnival" ],
+    "char": "\ud83c\udfa0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  building_construction: {
+    keywords: [ "wip", "working", "progress" ],
+    "char": "\ud83c\udfd7",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  foggy: {
+    keywords: [ "photo", "mountain" ],
+    "char": "\ud83c\udf01",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tokyo_tower: {
+    keywords: [ "photo", "japanese" ],
+    "char": "\ud83d\uddfc",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  factory: {
+    keywords: [ "building", "industry", "pollution", "smoke" ],
+    "char": "\ud83c\udfed",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fountain: {
+    keywords: [ "photo", "summer", "water", "fresh" ],
+    "char": "\u26f2",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rice_scene: {
+    keywords: [ "photo", "japan", "asia", "tsukimi" ],
+    "char": "\ud83c\udf91",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain: {
+    keywords: [ "photo", "nature", "environment" ],
+    "char": "\u26f0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mountain_snow: {
+    keywords: [ "photo", "nature", "environment", "winter", "cold" ],
+    "char": "\ud83c\udfd4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mount_fuji: {
+    keywords: [ "photo", "mountain", "nature", "japanese" ],
+    "char": "\ud83d\uddfb",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  volcano: {
+    keywords: [ "photo", "nature", "disaster" ],
+    "char": "\ud83c\udf0b",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  japan: {
+    keywords: [ "nation", "country", "japanese", "asia" ],
+    "char": "\ud83d\uddfe",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  camping: {
+    keywords: [ "photo", "outdoors", "tent" ],
+    "char": "\ud83c\udfd5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  tent: {
+    keywords: [ "photo", "camping", "outdoors" ],
+    "char": "\u26fa",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  national_park: {
+    keywords: [ "photo", "environment", "nature" ],
+    "char": "\ud83c\udfde",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  motorway: {
+    keywords: [ "road", "cupertino", "interstate", "highway" ],
+    "char": "\ud83d\udee3",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  railway_track: {
+    keywords: [ "train", "transportation" ],
+    "char": "\ud83d\udee4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sunrise: {
+    keywords: [ "morning", "view", "vacation", "photo" ],
+    "char": "\ud83c\udf05",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sunrise_over_mountains: {
+    keywords: [ "view", "vacation", "photo" ],
+    "char": "\ud83c\udf04",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  desert: {
+    keywords: [ "photo", "warm", "saharah" ],
+    "char": "\ud83c\udfdc",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  beach_umbrella: {
+    keywords: [ "weather", "summer", "sunny", "sand", "mojito" ],
+    "char": "\ud83c\udfd6",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  desert_island: {
+    keywords: [ "photo", "tropical", "mojito" ],
+    "char": "\ud83c\udfdd",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  city_sunrise: {
+    keywords: [ "photo", "good morning", "dawn" ],
+    "char": "\ud83c\udf07",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  city_sunset: {
+    keywords: [ "photo", "evening", "sky", "buildings" ],
+    "char": "\ud83c\udf06",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  cityscape: {
+    keywords: [ "photo", "night life", "urban" ],
+    "char": "\ud83c\udfd9",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  night_with_stars: {
+    keywords: [ "evening", "city", "downtown" ],
+    "char": "\ud83c\udf03",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bridge_at_night: {
+    keywords: [ "photo", "sanfrancisco" ],
+    "char": "\ud83c\udf09",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  milky_way: {
+    keywords: [ "photo", "space", "stars" ],
+    "char": "\ud83c\udf0c",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  stars: {
+    keywords: [ "night", "photo" ],
+    "char": "\ud83c\udf20",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  sparkler: {
+    keywords: [ "stars", "night", "shine" ],
+    "char": "\ud83c\udf87",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  fireworks: {
+    keywords: [ "photo", "festival", "carnival", "congratulations" ],
+    "char": "\ud83c\udf86",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  rainbow: {
+    keywords: [ "nature", "happy", "unicorn_face", "photo", "sky", "spring" ],
+    "char": "\ud83c\udf08",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  houses: {
+    keywords: [ "buildings", "photo" ],
+    "char": "\ud83c\udfd8",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  european_castle: {
+    keywords: [ "building", "royalty", "history" ],
+    "char": "\ud83c\udff0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  japanese_castle: {
+    keywords: [ "photo", "building" ],
+    "char": "\ud83c\udfef",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  stadium: {
+    keywords: [ "photo", "place", "sports", "concert", "venue" ],
+    "char": "\ud83c\udfdf",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  statue_of_liberty: {
+    keywords: [ "american", "newyork" ],
+    "char": "\ud83d\uddfd",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  house: {
+    keywords: [ "building", "home" ],
+    "char": "\ud83c\udfe0",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  house_with_garden: {
+    keywords: [ "home", "plant", "nature" ],
+    "char": "\ud83c\udfe1",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  derelict_house: {
+    keywords: [ "abandon", "evict", "broken", "building" ],
+    "char": "\ud83c\udfda",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  office: {
+    keywords: [ "building", "bureau", "work" ],
+    "char": "\ud83c\udfe2",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  department_store: {
+    keywords: [ "building", "shopping", "mall" ],
+    "char": "\ud83c\udfec",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  post_office: {
+    keywords: [ "building", "envelope", "communication" ],
+    "char": "\ud83c\udfe3",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  european_post_office: {
+    keywords: [ "building", "email" ],
+    "char": "\ud83c\udfe4",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  hospital: {
+    keywords: [ "building", "health", "surgery", "doctor" ],
+    "char": "\ud83c\udfe5",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  bank: {
+    keywords: [ "building", "money", "sales", "cash", "business", "enterprise" ],
+    "char": "\ud83c\udfe6",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  hotel: {
+    keywords: [ "building", "accomodation", "checkin" ],
+    "char": "\ud83c\udfe8",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  convenience_store: {
+    keywords: [ "building", "shopping", "groceries" ],
+    "char": "\ud83c\udfea",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  school: {
+    keywords: [ "building", "student", "education", "learn", "teach" ],
+    "char": "\ud83c\udfeb",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  love_hotel: {
+    keywords: [ "like", "affection", "dating" ],
+    "char": "\ud83c\udfe9",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  wedding: {
+    keywords: [ "love", "like", "affection", "couple", "marriage", "bride", "groom" ],
+    "char": "\ud83d\udc92",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  classical_building: {
+    keywords: [ "art", "culture", "history" ],
+    "char": "\ud83c\udfdb",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  church: {
+    keywords: [ "building", "religion", "christ" ],
+    "char": "\u26ea",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  mosque: {
+    keywords: [ "islam", "worship", "minaret" ],
+    "char": "\ud83d\udd4c",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  synagogue: {
+    keywords: [ "judaism", "worship", "temple", "jewish" ],
+    "char": "\ud83d\udd4d",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  kaaba: {
+    keywords: [ "mecca", "mosque", "islam" ],
+    "char": "\ud83d\udd4b",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  shinto_shrine: {
+    keywords: [ "temple", "japan", "kyoto" ],
+    "char": "\u26e9",
+    fitzpatrick_scale: false,
+    category: "travel_and_places"
+  },
+  watch: {
+    keywords: [ "time", "accessories" ],
+    "char": "\u231a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  iphone: {
+    keywords: [ "technology", "apple", "gadgets", "dial" ],
+    "char": "\ud83d\udcf1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  calling: {
+    keywords: [ "iphone", "incoming" ],
+    "char": "\ud83d\udcf2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  computer: {
+    keywords: [ "technology", "laptop", "screen", "display", "monitor" ],
+    "char": "\ud83d\udcbb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  keyboard: {
+    keywords: [ "technology", "computer", "type", "input", "text" ],
+    "char": "\u2328",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  desktop_computer: {
+    keywords: [ "technology", "computing", "screen" ],
+    "char": "\ud83d\udda5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  printer: {
+    keywords: [ "paper", "ink" ],
+    "char": "\ud83d\udda8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  computer_mouse: {
+    keywords: [ "click" ],
+    "char": "\ud83d\uddb1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  trackball: {
+    keywords: [ "technology", "trackpad" ],
+    "char": "\ud83d\uddb2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  joystick: {
+    keywords: [ "game", "play" ],
+    "char": "\ud83d\udd79",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  clamp: {
+    keywords: [ "tool" ],
+    "char": "\ud83d\udddc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  minidisc: {
+    keywords: [ "technology", "record", "data", "disk", "90s" ],
+    "char": "\ud83d\udcbd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  floppy_disk: {
+    keywords: [ "oldschool", "technology", "save", "90s", "80s" ],
+    "char": "\ud83d\udcbe",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  cd: {
+    keywords: [ "technology", "dvd", "disk", "disc", "90s" ],
+    "char": "\ud83d\udcbf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dvd: {
+    keywords: [ "cd", "disk", "disc" ],
+    "char": "\ud83d\udcc0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  vhs: {
+    keywords: [ "record", "video", "oldschool", "90s", "80s" ],
+    "char": "\ud83d\udcfc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  camera: {
+    keywords: [ "gadgets", "photography" ],
+    "char": "\ud83d\udcf7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  camera_flash: {
+    keywords: [ "photography", "gadgets" ],
+    "char": "\ud83d\udcf8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  video_camera: {
+    keywords: [ "film", "record" ],
+    "char": "\ud83d\udcf9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  movie_camera: {
+    keywords: [ "film", "record" ],
+    "char": "\ud83c\udfa5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  film_projector: {
+    keywords: [ "video", "tape", "record", "movie" ],
+    "char": "\ud83d\udcfd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  film_strip: {
+    keywords: [ "movie" ],
+    "char": "\ud83c\udf9e",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  telephone_receiver: {
+    keywords: [ "technology", "communication", "dial" ],
+    "char": "\ud83d\udcde",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  phone: {
+    keywords: [ "technology", "communication", "dial", "telephone" ],
+    "char": "\u260e\ufe0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pager: {
+    keywords: [ "bbcall", "oldschool", "90s" ],
+    "char": "\ud83d\udcdf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fax: {
+    keywords: [ "communication", "technology" ],
+    "char": "\ud83d\udce0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  tv: {
+    keywords: [ "technology", "program", "oldschool", "show", "television" ],
+    "char": "\ud83d\udcfa",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  radio: {
+    keywords: [ "communication", "music", "podcast", "program" ],
+    "char": "\ud83d\udcfb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  studio_microphone: {
+    keywords: [ "sing", "recording", "artist", "talkshow" ],
+    "char": "\ud83c\udf99",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  level_slider: {
+    keywords: [ "scale" ],
+    "char": "\ud83c\udf9a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  control_knobs: {
+    keywords: [ "dial" ],
+    "char": "\ud83c\udf9b",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  compass: {
+    keywords: [ "magnetic", "navigation", "orienteering" ],
+    "char": "\ud83e\udded",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  stopwatch: {
+    keywords: [ "time", "deadline" ],
+    "char": "\u23f1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  timer_clock: {
+    keywords: [ "alarm" ],
+    "char": "\u23f2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  alarm_clock: {
+    keywords: [ "time", "wake" ],
+    "char": "\u23f0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mantelpiece_clock: {
+    keywords: [ "time" ],
+    "char": "\ud83d\udd70",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hourglass_flowing_sand: {
+    keywords: [ "oldschool", "time", "countdown" ],
+    "char": "\u23f3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hourglass: {
+    keywords: [ "time", "clock", "oldschool", "limit", "exam", "quiz", "test" ],
+    "char": "\u231b",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  satellite: {
+    keywords: [ "communication", "future", "radio", "space" ],
+    "char": "\ud83d\udce1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  battery: {
+    keywords: [ "power", "energy", "sustain" ],
+    "char": "\ud83d\udd0b",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  electric_plug: {
+    keywords: [ "charger", "power" ],
+    "char": "\ud83d\udd0c",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bulb: {
+    keywords: [ "light", "electricity", "idea" ],
+    "char": "\ud83d\udca1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  flashlight: {
+    keywords: [ "dark", "camping", "sight", "night" ],
+    "char": "\ud83d\udd26",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  candle: {
+    keywords: [ "fire", "wax" ],
+    "char": "\ud83d\udd6f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fire_extinguisher: {
+    keywords: [ "quench" ],
+    "char": "\ud83e\uddef",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wastebasket: {
+    keywords: [ "bin", "trash", "rubbish", "garbage", "toss" ],
+    "char": "\ud83d\uddd1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  oil_drum: {
+    keywords: [ "barrell" ],
+    "char": "\ud83d\udee2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  money_with_wings: {
+    keywords: [ "dollar", "bills", "payment", "sale" ],
+    "char": "\ud83d\udcb8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dollar: {
+    keywords: [ "money", "sales", "bill", "currency" ],
+    "char": "\ud83d\udcb5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  yen: {
+    keywords: [ "money", "sales", "japanese", "dollar", "currency" ],
+    "char": "\ud83d\udcb4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  euro: {
+    keywords: [ "money", "sales", "dollar", "currency" ],
+    "char": "\ud83d\udcb6",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pound: {
+    keywords: [ "british", "sterling", "money", "sales", "bills", "uk", "england", "currency" ],
+    "char": "\ud83d\udcb7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  moneybag: {
+    keywords: [ "dollar", "payment", "coins", "sale" ],
+    "char": "\ud83d\udcb0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  credit_card: {
+    keywords: [ "money", "sales", "dollar", "bill", "payment", "shopping" ],
+    "char": "\ud83d\udcb3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gem: {
+    keywords: [ "blue", "ruby", "diamond", "jewelry" ],
+    "char": "\ud83d\udc8e",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  balance_scale: {
+    keywords: [ "law", "fairness", "weight" ],
+    "char": "\u2696",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toolbox: {
+    keywords: [ "tools", "diy", "fix", "maintainer", "mechanic" ],
+    "char": "\ud83e\uddf0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wrench: {
+    keywords: [ "tools", "diy", "ikea", "fix", "maintainer" ],
+    "char": "\ud83d\udd27",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer: {
+    keywords: [ "tools", "build", "create" ],
+    "char": "\ud83d\udd28",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer_and_pick: {
+    keywords: [ "tools", "build", "create" ],
+    "char": "\u2692",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hammer_and_wrench: {
+    keywords: [ "tools", "build", "create" ],
+    "char": "\ud83d\udee0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pick: {
+    keywords: [ "tools", "dig" ],
+    "char": "\u26cf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  nut_and_bolt: {
+    keywords: [ "handy", "tools", "fix" ],
+    "char": "\ud83d\udd29",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gear: {
+    keywords: [ "cog" ],
+    "char": "\u2699",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  brick: {
+    keywords: [ "bricks" ],
+    "char": "\ud83e\uddf1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chains: {
+    keywords: [ "lock", "arrest" ],
+    "char": "\u26d3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  magnet: {
+    keywords: [ "attraction", "magnetic" ],
+    "char": "\ud83e\uddf2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gun: {
+    keywords: [ "violence", "weapon", "pistol", "revolver" ],
+    "char": "\ud83d\udd2b",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bomb: {
+    keywords: [ "boom", "explode", "explosion", "terrorism" ],
+    "char": "\ud83d\udca3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  firecracker: {
+    keywords: [ "dynamite", "boom", "explode", "explosion", "explosive" ],
+    "char": "\ud83e\udde8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hocho: {
+    keywords: [ "knife", "blade", "cutlery", "kitchen", "weapon" ],
+    "char": "\ud83d\udd2a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dagger: {
+    keywords: [ "weapon" ],
+    "char": "\ud83d\udde1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crossed_swords: {
+    keywords: [ "weapon" ],
+    "char": "\u2694",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shield: {
+    keywords: [ "protection", "security" ],
+    "char": "\ud83d\udee1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  smoking: {
+    keywords: [ "kills", "tobacco", "cigarette", "joint", "smoke" ],
+    "char": "\ud83d\udeac",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  skull_and_crossbones: {
+    keywords: [ "poison", "danger", "deadly", "scary", "death", "pirate", "evil" ],
+    "char": "\u2620",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  coffin: {
+    keywords: [ "vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box" ],
+    "char": "\u26b0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  funeral_urn: {
+    keywords: [ "dead", "die", "death", "rip", "ashes" ],
+    "char": "\u26b1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  amphora: {
+    keywords: [ "vase", "jar" ],
+    "char": "\ud83c\udffa",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crystal_ball: {
+    keywords: [ "disco", "party", "magic", "circus", "fortune_teller" ],
+    "char": "\ud83d\udd2e",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  prayer_beads: {
+    keywords: [ "dhikr", "religious" ],
+    "char": "\ud83d\udcff",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  nazar_amulet: {
+    keywords: [ "bead", "charm" ],
+    "char": "\ud83e\uddff",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  barber: {
+    keywords: [ "hair", "salon", "style" ],
+    "char": "\ud83d\udc88",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  alembic: {
+    keywords: [ "distilling", "science", "experiment", "chemistry" ],
+    "char": "\u2697",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  telescope: {
+    keywords: [ "stars", "space", "zoom", "science", "astronomy" ],
+    "char": "\ud83d\udd2d",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  microscope: {
+    keywords: [ "laboratory", "experiment", "zoomin", "science", "study" ],
+    "char": "\ud83d\udd2c",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  hole: {
+    keywords: [ "embarrassing" ],
+    "char": "\ud83d\udd73",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pill: {
+    keywords: [ "health", "medicine", "doctor", "pharmacy", "drug" ],
+    "char": "\ud83d\udc8a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  syringe: {
+    keywords: [ "health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse" ],
+    "char": "\ud83d\udc89",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dna: {
+    keywords: [ "biologist", "genetics", "life" ],
+    "char": "\ud83e\uddec",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  microbe: {
+    keywords: [ "amoeba", "bacteria", "germs" ],
+    "char": "\ud83e\udda0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  petri_dish: {
+    keywords: [ "bacteria", "biology", "culture", "lab" ],
+    "char": "\ud83e\uddeb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  test_tube: {
+    keywords: [ "chemistry", "experiment", "lab", "science" ],
+    "char": "\ud83e\uddea",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  thermometer: {
+    keywords: [ "weather", "temperature", "hot", "cold" ],
+    "char": "\ud83c\udf21",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  broom: {
+    keywords: [ "cleaning", "sweeping", "witch" ],
+    "char": "\ud83e\uddf9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  basket: {
+    keywords: [ "laundry" ],
+    "char": "\ud83e\uddfa",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toilet_paper: {
+    keywords: [ "roll" ],
+    "char": "\ud83e\uddfb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  label: {
+    keywords: [ "sale", "tag" ],
+    "char": "\ud83c\udff7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bookmark: {
+    keywords: [ "favorite", "label", "save" ],
+    "char": "\ud83d\udd16",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  toilet: {
+    keywords: [ "restroom", "wc", "washroom", "bathroom", "potty" ],
+    "char": "\ud83d\udebd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shower: {
+    keywords: [ "clean", "water", "bathroom" ],
+    "char": "\ud83d\udebf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bathtub: {
+    keywords: [ "clean", "shower", "bathroom" ],
+    "char": "\ud83d\udec1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  soap: {
+    keywords: [ "bar", "bathing", "cleaning", "lather" ],
+    "char": "\ud83e\uddfc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  sponge: {
+    keywords: [ "absorbing", "cleaning", "porous" ],
+    "char": "\ud83e\uddfd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lotion_bottle: {
+    keywords: [ "moisturizer", "sunscreen" ],
+    "char": "\ud83e\uddf4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  key: {
+    keywords: [ "lock", "door", "password" ],
+    "char": "\ud83d\udd11",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  old_key: {
+    keywords: [ "lock", "door", "password" ],
+    "char": "\ud83d\udddd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  couch_and_lamp: {
+    keywords: [ "read", "chill" ],
+    "char": "\ud83d\udecb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  sleeping_bed: {
+    keywords: [ "bed", "rest" ],
+    "char": "\ud83d\udecc",
+    fitzpatrick_scale: true,
+    category: "objects"
+  },
+  bed: {
+    keywords: [ "sleep", "rest" ],
+    "char": "\ud83d\udecf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  door: {
+    keywords: [ "house", "entry", "exit" ],
+    "char": "\ud83d\udeaa",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bellhop_bell: {
+    keywords: [ "service" ],
+    "char": "\ud83d\udece",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  teddy_bear: {
+    keywords: [ "plush", "stuffed" ],
+    "char": "\ud83e\uddf8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  framed_picture: {
+    keywords: [ "photography" ],
+    "char": "\ud83d\uddbc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  world_map: {
+    keywords: [ "location", "direction" ],
+    "char": "\ud83d\uddfa",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  parasol_on_ground: {
+    keywords: [ "weather", "summer" ],
+    "char": "\u26f1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  moyai: {
+    keywords: [ "rock", "easter island", "moai" ],
+    "char": "\ud83d\uddff",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shopping: {
+    keywords: [ "mall", "buy", "purchase" ],
+    "char": "\ud83d\udecd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  shopping_cart: {
+    keywords: [ "trolley" ],
+    "char": "\ud83d\uded2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  balloon: {
+    keywords: [ "party", "celebration", "birthday", "circus" ],
+    "char": "\ud83c\udf88",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  flags: {
+    keywords: [ "fish", "japanese", "koinobori", "carp", "banner" ],
+    "char": "\ud83c\udf8f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ribbon: {
+    keywords: [ "decoration", "pink", "girl", "bowtie" ],
+    "char": "\ud83c\udf80",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  gift: {
+    keywords: [ "present", "birthday", "christmas", "xmas" ],
+    "char": "\ud83c\udf81",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  confetti_ball: {
+    keywords: [ "festival", "party", "birthday", "circus" ],
+    "char": "\ud83c\udf8a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  tada: {
+    keywords: [ "party", "congratulations", "birthday", "magic", "circus", "celebration" ],
+    "char": "\ud83c\udf89",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  dolls: {
+    keywords: [ "japanese", "toy", "kimono" ],
+    "char": "\ud83c\udf8e",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  wind_chime: {
+    keywords: [ "nature", "ding", "spring", "bell" ],
+    "char": "\ud83c\udf90",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crossed_flags: {
+    keywords: [ "japanese", "nation", "country", "border" ],
+    "char": "\ud83c\udf8c",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  izakaya_lantern: {
+    keywords: [ "light", "paper", "halloween", "spooky" ],
+    "char": "\ud83c\udfee",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  red_envelope: {
+    keywords: [ "gift" ],
+    "char": "\ud83e\udde7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  email: {
+    keywords: [ "letter", "postal", "inbox", "communication" ],
+    "char": "\u2709\ufe0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  envelope_with_arrow: {
+    keywords: [ "email", "communication" ],
+    "char": "\ud83d\udce9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  incoming_envelope: {
+    keywords: [ "email", "inbox" ],
+    "char": "\ud83d\udce8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  "e-mail": {
+    keywords: [ "communication", "inbox" ],
+    "char": "\ud83d\udce7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  love_letter: {
+    keywords: [ "email", "like", "affection", "envelope", "valentines" ],
+    "char": "\ud83d\udc8c",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  postbox: {
+    keywords: [ "email", "letter", "envelope" ],
+    "char": "\ud83d\udcee",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_closed: {
+    keywords: [ "email", "communication", "inbox" ],
+    "char": "\ud83d\udcea",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox: {
+    keywords: [ "email", "inbox", "communication" ],
+    "char": "\ud83d\udceb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_with_mail: {
+    keywords: [ "email", "inbox", "communication" ],
+    "char": "\ud83d\udcec",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mailbox_with_no_mail: {
+    keywords: [ "email", "inbox" ],
+    "char": "\ud83d\udced",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  "package": {
+    keywords: [ "mail", "gift", "cardboard", "box", "moving" ],
+    "char": "\ud83d\udce6",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  postal_horn: {
+    keywords: [ "instrument", "music" ],
+    "char": "\ud83d\udcef",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  inbox_tray: {
+    keywords: [ "email", "documents" ],
+    "char": "\ud83d\udce5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  outbox_tray: {
+    keywords: [ "inbox", "email" ],
+    "char": "\ud83d\udce4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  scroll: {
+    keywords: [ "documents", "ancient", "history", "paper" ],
+    "char": "\ud83d\udcdc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  page_with_curl: {
+    keywords: [ "documents", "office", "paper" ],
+    "char": "\ud83d\udcc3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bookmark_tabs: {
+    keywords: [ "favorite", "save", "order", "tidy" ],
+    "char": "\ud83d\udcd1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  receipt: {
+    keywords: [ "accounting", "expenses" ],
+    "char": "\ud83e\uddfe",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  bar_chart: {
+    keywords: [ "graph", "presentation", "stats" ],
+    "char": "\ud83d\udcca",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chart_with_upwards_trend: {
+    keywords: [ "graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success" ],
+    "char": "\ud83d\udcc8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  chart_with_downwards_trend: {
+    keywords: [ "graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure" ],
+    "char": "\ud83d\udcc9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  page_facing_up: {
+    keywords: [ "documents", "office", "paper", "information" ],
+    "char": "\ud83d\udcc4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  date: {
+    keywords: [ "calendar", "schedule" ],
+    "char": "\ud83d\udcc5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  calendar: {
+    keywords: [ "schedule", "date", "planning" ],
+    "char": "\ud83d\udcc6",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  spiral_calendar: {
+    keywords: [ "date", "schedule", "planning" ],
+    "char": "\ud83d\uddd3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_index: {
+    keywords: [ "business", "stationery" ],
+    "char": "\ud83d\udcc7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_file_box: {
+    keywords: [ "business", "stationery" ],
+    "char": "\ud83d\uddc3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ballot_box: {
+    keywords: [ "election", "vote" ],
+    "char": "\ud83d\uddf3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  file_cabinet: {
+    keywords: [ "filing", "organizing" ],
+    "char": "\ud83d\uddc4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  clipboard: {
+    keywords: [ "stationery", "documents" ],
+    "char": "\ud83d\udccb",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  spiral_notepad: {
+    keywords: [ "memo", "stationery" ],
+    "char": "\ud83d\uddd2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  file_folder: {
+    keywords: [ "documents", "business", "office" ],
+    "char": "\ud83d\udcc1",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  open_file_folder: {
+    keywords: [ "documents", "load" ],
+    "char": "\ud83d\udcc2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  card_index_dividers: {
+    keywords: [ "organizing", "business", "stationery" ],
+    "char": "\ud83d\uddc2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  newspaper_roll: {
+    keywords: [ "press", "headline" ],
+    "char": "\ud83d\uddde",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  newspaper: {
+    keywords: [ "press", "headline" ],
+    "char": "\ud83d\udcf0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  notebook: {
+    keywords: [ "stationery", "record", "notes", "paper", "study" ],
+    "char": "\ud83d\udcd3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  closed_book: {
+    keywords: [ "read", "library", "knowledge", "textbook", "learn" ],
+    "char": "\ud83d\udcd5",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  green_book: {
+    keywords: [ "read", "library", "knowledge", "study" ],
+    "char": "\ud83d\udcd7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  blue_book: {
+    keywords: [ "read", "library", "knowledge", "learn", "study" ],
+    "char": "\ud83d\udcd8",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  orange_book: {
+    keywords: [ "read", "library", "knowledge", "textbook", "study" ],
+    "char": "\ud83d\udcd9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  notebook_with_decorative_cover: {
+    keywords: [ "classroom", "notes", "record", "paper", "study" ],
+    "char": "\ud83d\udcd4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  ledger: {
+    keywords: [ "notes", "paper" ],
+    "char": "\ud83d\udcd2",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  books: {
+    keywords: [ "literature", "library", "study" ],
+    "char": "\ud83d\udcda",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  open_book: {
+    keywords: [ "book", "read", "library", "knowledge", "literature", "learn", "study" ],
+    "char": "\ud83d\udcd6",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  safety_pin: {
+    keywords: [ "diaper" ],
+    "char": "\ud83e\uddf7",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  link: {
+    keywords: [ "rings", "url" ],
+    "char": "\ud83d\udd17",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paperclip: {
+    keywords: [ "documents", "stationery" ],
+    "char": "\ud83d\udcce",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paperclips: {
+    keywords: [ "documents", "stationery" ],
+    "char": "\ud83d\udd87",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  scissors: {
+    keywords: [ "stationery", "cut" ],
+    "char": "\u2702\ufe0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  triangular_ruler: {
+    keywords: [ "stationery", "math", "architect", "sketch" ],
+    "char": "\ud83d\udcd0",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  straight_ruler: {
+    keywords: [ "stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch" ],
+    "char": "\ud83d\udccf",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  abacus: {
+    keywords: [ "calculation" ],
+    "char": "\ud83e\uddee",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pushpin: {
+    keywords: [ "stationery", "mark", "here" ],
+    "char": "\ud83d\udccc",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  round_pushpin: {
+    keywords: [ "stationery", "location", "map", "here" ],
+    "char": "\ud83d\udccd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  triangular_flag_on_post: {
+    keywords: [ "mark", "milestone", "place" ],
+    "char": "\ud83d\udea9",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  white_flag: {
+    keywords: [ "losing", "loser", "lost", "surrender", "give up", "fail" ],
+    "char": "\ud83c\udff3",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  black_flag: {
+    keywords: [ "pirate" ],
+    "char": "\ud83c\udff4",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  rainbow_flag: {
+    keywords: [ "flag", "rainbow", "pride", "gay", "lgbt", "glbt", "queer", "homosexual", "lesbian", "bisexual", "transgender" ],
+    "char": "\ud83c\udff3\ufe0f\u200d\ud83c\udf08",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  closed_lock_with_key: {
+    keywords: [ "security", "privacy" ],
+    "char": "\ud83d\udd10",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lock: {
+    keywords: [ "security", "password", "padlock" ],
+    "char": "\ud83d\udd12",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  unlock: {
+    keywords: [ "privacy", "security" ],
+    "char": "\ud83d\udd13",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  lock_with_ink_pen: {
+    keywords: [ "security", "secret" ],
+    "char": "\ud83d\udd0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pen: {
+    keywords: [ "stationery", "writing", "write" ],
+    "char": "\ud83d\udd8a",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  fountain_pen: {
+    keywords: [ "stationery", "writing", "write" ],
+    "char": "\ud83d\udd8b",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  black_nib: {
+    keywords: [ "pen", "stationery", "writing", "write" ],
+    "char": "\u2712\ufe0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  memo: {
+    keywords: [ "write", "documents", "stationery", "pencil", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose" ],
+    "char": "\ud83d\udcdd",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  pencil2: {
+    keywords: [ "stationery", "write", "paper", "writing", "school", "study" ],
+    "char": "\u270f\ufe0f",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  crayon: {
+    keywords: [ "drawing", "creativity" ],
+    "char": "\ud83d\udd8d",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  paintbrush: {
+    keywords: [ "drawing", "creativity", "art" ],
+    "char": "\ud83d\udd8c",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mag: {
+    keywords: [ "search", "zoom", "find", "detective" ],
+    "char": "\ud83d\udd0d",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  mag_right: {
+    keywords: [ "search", "zoom", "find", "detective" ],
+    "char": "\ud83d\udd0e",
+    fitzpatrick_scale: false,
+    category: "objects"
+  },
+  heart: {
+    keywords: [ "love", "like", "valentines" ],
+    "char": "\u2764\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  orange_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83e\udde1",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  yellow_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc9b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  green_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc9a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  blue_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc99",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  purple_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc9c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_heart: {
+    keywords: [ "evil" ],
+    "char": "\ud83d\udda4",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  broken_heart: {
+    keywords: [ "sad", "sorry", "break", "heart", "heartbreak" ],
+    "char": "\ud83d\udc94",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_heart_exclamation: {
+    keywords: [ "decoration", "love" ],
+    "char": "\u2763",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  two_hearts: {
+    keywords: [ "love", "like", "affection", "valentines", "heart" ],
+    "char": "\ud83d\udc95",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  revolving_hearts: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc9e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heartbeat: {
+    keywords: [ "love", "like", "affection", "valentines", "pink", "heart" ],
+    "char": "\ud83d\udc93",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heartpulse: {
+    keywords: [ "like", "love", "affection", "valentines", "pink" ],
+    "char": "\ud83d\udc97",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sparkling_heart: {
+    keywords: [ "love", "like", "affection", "valentines" ],
+    "char": "\ud83d\udc96",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cupid: {
+    keywords: [ "love", "like", "heart", "affection", "valentines" ],
+    "char": "\ud83d\udc98",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  gift_heart: {
+    keywords: [ "love", "valentines" ],
+    "char": "\ud83d\udc9d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heart_decoration: {
+    keywords: [ "purple-square", "love", "like" ],
+    "char": "\ud83d\udc9f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  peace_symbol: {
+    keywords: [ "hippie" ],
+    "char": "\u262e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  latin_cross: {
+    keywords: [ "christianity" ],
+    "char": "\u271d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  star_and_crescent: {
+    keywords: [ "islam" ],
+    "char": "\u262a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  om: {
+    keywords: [ "hinduism", "buddhism", "sikhism", "jainism" ],
+    "char": "\ud83d\udd49",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wheel_of_dharma: {
+    keywords: [ "hinduism", "buddhism", "sikhism", "jainism" ],
+    "char": "\u2638",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  star_of_david: {
+    keywords: [ "judaism" ],
+    "char": "\u2721",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  six_pointed_star: {
+    keywords: [ "purple-square", "religion", "jewish", "hexagram" ],
+    "char": "\ud83d\udd2f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  menorah: {
+    keywords: [ "hanukkah", "candles", "jewish" ],
+    "char": "\ud83d\udd4e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  yin_yang: {
+    keywords: [ "balance" ],
+    "char": "\u262f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  orthodox_cross: {
+    keywords: [ "suppedaneum", "religion" ],
+    "char": "\u2626",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  place_of_worship: {
+    keywords: [ "religion", "church", "temple", "prayer" ],
+    "char": "\ud83d\uded0",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ophiuchus: {
+    keywords: [ "sign", "purple-square", "constellation", "astrology" ],
+    "char": "\u26ce",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  aries: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": "\u2648",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  taurus: {
+    keywords: [ "purple-square", "sign", "zodiac", "astrology" ],
+    "char": "\u2649",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  gemini: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": "\u264a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cancer: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": "\u264b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  leo: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": "\u264c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  virgo: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": "\u264d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  libra: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": "\u264e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  scorpius: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology", "scorpio" ],
+    "char": "\u264f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sagittarius: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": "\u2650",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  capricorn: {
+    keywords: [ "sign", "zodiac", "purple-square", "astrology" ],
+    "char": "\u2651",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  aquarius: {
+    keywords: [ "sign", "purple-square", "zodiac", "astrology" ],
+    "char": "\u2652",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  pisces: {
+    keywords: [ "purple-square", "sign", "zodiac", "astrology" ],
+    "char": "\u2653",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  id: {
+    keywords: [ "purple-square", "words" ],
+    "char": "\ud83c\udd94",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  atom_symbol: {
+    keywords: [ "science", "physics", "chemistry" ],
+    "char": "\u269b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7a7a: {
+    keywords: [ "kanji", "japanese", "chinese", "empty", "sky", "blue-square" ],
+    "char": "\ud83c\ude33",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u5272: {
+    keywords: [ "cut", "divide", "chinese", "kanji", "pink-square" ],
+    "char": "\ud83c\ude39",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  radioactive: {
+    keywords: [ "nuclear", "danger" ],
+    "char": "\u2622",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  biohazard: {
+    keywords: [ "danger" ],
+    "char": "\u2623",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mobile_phone_off: {
+    keywords: [ "mute", "orange-square", "silence", "quiet" ],
+    "char": "\ud83d\udcf4",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  vibration_mode: {
+    keywords: [ "orange-square", "phone" ],
+    "char": "\ud83d\udcf3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6709: {
+    keywords: [ "orange-square", "chinese", "have", "kanji" ],
+    "char": "\ud83c\ude36",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7121: {
+    keywords: [ "nothing", "chinese", "kanji", "japanese", "orange-square" ],
+    "char": "\ud83c\ude1a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7533: {
+    keywords: [ "chinese", "japanese", "kanji", "orange-square" ],
+    "char": "\ud83c\ude38",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u55b6: {
+    keywords: [ "japanese", "opening hours", "orange-square" ],
+    "char": "\ud83c\ude3a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6708: {
+    keywords: [ "chinese", "month", "moon", "japanese", "orange-square", "kanji" ],
+    "char": "\ud83c\ude37\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight_pointed_black_star: {
+    keywords: [ "orange-square", "shape", "polygon" ],
+    "char": "\u2734\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  vs: {
+    keywords: [ "words", "orange-square" ],
+    "char": "\ud83c\udd9a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  accept: {
+    keywords: [ "ok", "good", "chinese", "kanji", "agree", "yes", "orange-circle" ],
+    "char": "\ud83c\ude51",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_flower: {
+    keywords: [ "japanese", "spring" ],
+    "char": "\ud83d\udcae",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ideograph_advantage: {
+    keywords: [ "chinese", "kanji", "obtain", "get", "circle" ],
+    "char": "\ud83c\ude50",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  secret: {
+    keywords: [ "privacy", "chinese", "sshh", "kanji", "red-circle" ],
+    "char": "\u3299\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  congratulations: {
+    keywords: [ "chinese", "kanji", "japanese", "red-circle" ],
+    "char": "\u3297\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u5408: {
+    keywords: [ "japanese", "chinese", "join", "kanji", "red-square" ],
+    "char": "\ud83c\ude34",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6e80: {
+    keywords: [ "full", "chinese", "japanese", "red-square", "kanji" ],
+    "char": "\ud83c\ude35",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u7981: {
+    keywords: [ "kanji", "japanese", "chinese", "forbidden", "limit", "restricted", "red-square" ],
+    "char": "\ud83c\ude32",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  a: {
+    keywords: [ "red-square", "alphabet", "letter" ],
+    "char": "\ud83c\udd70\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  b: {
+    keywords: [ "red-square", "alphabet", "letter" ],
+    "char": "\ud83c\udd71\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ab: {
+    keywords: [ "red-square", "alphabet" ],
+    "char": "\ud83c\udd8e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cl: {
+    keywords: [ "alphabet", "words", "red-square" ],
+    "char": "\ud83c\udd91",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  o2: {
+    keywords: [ "alphabet", "red-square", "letter" ],
+    "char": "\ud83c\udd7e\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sos: {
+    keywords: [ "help", "red-square", "words", "emergency", "911" ],
+    "char": "\ud83c\udd98",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_entry: {
+    keywords: [ "limit", "security", "privacy", "bad", "denied", "stop", "circle" ],
+    "char": "\u26d4",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  name_badge: {
+    keywords: [ "fire", "forbid" ],
+    "char": "\ud83d\udcdb",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_entry_sign: {
+    keywords: [ "forbid", "stop", "limit", "denied", "disallow", "circle" ],
+    "char": "\ud83d\udeab",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  x: {
+    keywords: [ "no", "delete", "remove", "cancel", "red" ],
+    "char": "\u274c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  o: {
+    keywords: [ "circle", "round" ],
+    "char": "\u2b55",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  stop_sign: {
+    keywords: [ "stop" ],
+    "char": "\ud83d\uded1",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  anger: {
+    keywords: [ "angry", "mad" ],
+    "char": "\ud83d\udca2",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hotsprings: {
+    keywords: [ "bath", "warm", "relax" ],
+    "char": "\u2668\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_pedestrians: {
+    keywords: [ "rules", "crossing", "walking", "circle" ],
+    "char": "\ud83d\udeb7",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  do_not_litter: {
+    keywords: [ "trash", "bin", "garbage", "circle" ],
+    "char": "\ud83d\udeaf",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_bicycles: {
+    keywords: [ "cyclist", "prohibited", "circle" ],
+    "char": "\ud83d\udeb3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  "non-potable_water": {
+    keywords: [ "drink", "faucet", "tap", "circle" ],
+    "char": "\ud83d\udeb1",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  underage: {
+    keywords: [ "18", "drink", "pub", "night", "minor", "circle" ],
+    "char": "\ud83d\udd1e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_mobile_phones: {
+    keywords: [ "iphone", "mute", "circle" ],
+    "char": "\ud83d\udcf5",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  exclamation: {
+    keywords: [ "heavy_exclamation_mark", "danger", "surprise", "punctuation", "wow", "warning" ],
+    "char": "\u2757",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  grey_exclamation: {
+    keywords: [ "surprise", "punctuation", "gray", "wow", "warning" ],
+    "char": "\u2755",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  question: {
+    keywords: [ "doubt", "confused" ],
+    "char": "\u2753",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  grey_question: {
+    keywords: [ "doubts", "gray", "huh", "confused" ],
+    "char": "\u2754",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  bangbang: {
+    keywords: [ "exclamation", "surprise" ],
+    "char": "\u203c\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  interrobang: {
+    keywords: [ "wat", "punctuation", "surprise" ],
+    "char": "\u2049\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  100: {
+    keywords: [ "score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred" ],
+    "char": "\ud83d\udcaf",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  low_brightness: {
+    keywords: [ "sun", "afternoon", "warm", "summer" ],
+    "char": "\ud83d\udd05",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  high_brightness: {
+    keywords: [ "sun", "light" ],
+    "char": "\ud83d\udd06",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  trident: {
+    keywords: [ "weapon", "spear" ],
+    "char": "\ud83d\udd31",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  fleur_de_lis: {
+    keywords: [ "decorative", "scout" ],
+    "char": "\u269c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  part_alternation_mark: {
+    keywords: [ "graph", "presentation", "stats", "business", "economics", "bad" ],
+    "char": "\u303d\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  warning: {
+    keywords: [ "exclamation", "wip", "alert", "error", "problem", "issue" ],
+    "char": "\u26a0\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  children_crossing: {
+    keywords: [ "school", "warning", "danger", "sign", "driving", "yellow-diamond" ],
+    "char": "\ud83d\udeb8",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  beginner: {
+    keywords: [ "badge", "shield" ],
+    "char": "\ud83d\udd30",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  recycle: {
+    keywords: [ "arrow", "environment", "garbage", "trash" ],
+    "char": "\u267b\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  u6307: {
+    keywords: [ "chinese", "point", "green-square", "kanji" ],
+    "char": "\ud83c\ude2f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  chart: {
+    keywords: [ "green-square", "graph", "presentation", "stats" ],
+    "char": "\ud83d\udcb9",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sparkle: {
+    keywords: [ "stars", "green-square", "awesome", "good", "fireworks" ],
+    "char": "\u2747\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight_spoked_asterisk: {
+    keywords: [ "star", "sparkle", "green-square" ],
+    "char": "\u2733\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  negative_squared_cross_mark: {
+    keywords: [ "x", "green-square", "no", "deny" ],
+    "char": "\u274e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_check_mark: {
+    keywords: [ "green-square", "ok", "agree", "vote", "election", "answer", "tick" ],
+    "char": "\u2705",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  diamond_shape_with_a_dot_inside: {
+    keywords: [ "jewel", "blue", "gem", "crystal", "fancy" ],
+    "char": "\ud83d\udca0",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cyclone: {
+    keywords: [ "weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon" ],
+    "char": "\ud83c\udf00",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loop: {
+    keywords: [ "tape", "cassette" ],
+    "char": "\u27bf",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  globe_with_meridians: {
+    keywords: [ "earth", "international", "world", "internet", "interweb", "i18n" ],
+    "char": "\ud83c\udf10",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  m: {
+    keywords: [ "alphabet", "blue-circle", "letter" ],
+    "char": "\u24c2\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  atm: {
+    keywords: [ "money", "sales", "cash", "blue-square", "payment", "bank" ],
+    "char": "\ud83c\udfe7",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sa: {
+    keywords: [ "japanese", "blue-square", "katakana" ],
+    "char": "\ud83c\ude02\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  passport_control: {
+    keywords: [ "custom", "blue-square" ],
+    "char": "\ud83d\udec2",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  customs: {
+    keywords: [ "passport", "border", "blue-square" ],
+    "char": "\ud83d\udec3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  baggage_claim: {
+    keywords: [ "blue-square", "airport", "transport" ],
+    "char": "\ud83d\udec4",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_luggage: {
+    keywords: [ "blue-square", "travel" ],
+    "char": "\ud83d\udec5",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wheelchair: {
+    keywords: [ "blue-square", "disabled", "a11y", "accessibility" ],
+    "char": "\u267f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_smoking: {
+    keywords: [ "cigarette", "blue-square", "smell", "smoke" ],
+    "char": "\ud83d\udead",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wc: {
+    keywords: [ "toilet", "restroom", "blue-square" ],
+    "char": "\ud83d\udebe",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  parking: {
+    keywords: [ "cars", "blue-square", "alphabet", "letter" ],
+    "char": "\ud83c\udd7f\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  potable_water: {
+    keywords: [ "blue-square", "liquid", "restroom", "cleaning", "faucet" ],
+    "char": "\ud83d\udeb0",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mens: {
+    keywords: [ "toilet", "restroom", "wc", "blue-square", "gender", "male" ],
+    "char": "\ud83d\udeb9",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  womens: {
+    keywords: [ "purple-square", "woman", "female", "toilet", "loo", "restroom", "gender" ],
+    "char": "\ud83d\udeba",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  baby_symbol: {
+    keywords: [ "orange-square", "child" ],
+    "char": "\ud83d\udebc",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  restroom: {
+    keywords: [ "blue-square", "toilet", "refresh", "wc", "gender" ],
+    "char": "\ud83d\udebb",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  put_litter_in_its_place: {
+    keywords: [ "blue-square", "sign", "human", "info" ],
+    "char": "\ud83d\udeae",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cinema: {
+    keywords: [ "blue-square", "record", "film", "movie", "curtain", "stage", "theater" ],
+    "char": "\ud83c\udfa6",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  signal_strength: {
+    keywords: [ "blue-square", "reception", "phone", "internet", "connection", "wifi", "bluetooth", "bars" ],
+    "char": "\ud83d\udcf6",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  koko: {
+    keywords: [ "blue-square", "here", "katakana", "japanese", "destination" ],
+    "char": "\ud83c\ude01",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ng: {
+    keywords: [ "blue-square", "words", "shape", "icon" ],
+    "char": "\ud83c\udd96",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ok: {
+    keywords: [ "good", "agree", "yes", "blue-square" ],
+    "char": "\ud83c\udd97",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  up: {
+    keywords: [ "blue-square", "above", "high" ],
+    "char": "\ud83c\udd99",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  cool: {
+    keywords: [ "words", "blue-square" ],
+    "char": "\ud83c\udd92",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  "new": {
+    keywords: [ "blue-square", "words", "start" ],
+    "char": "\ud83c\udd95",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  free: {
+    keywords: [ "blue-square", "words" ],
+    "char": "\ud83c\udd93",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  zero: {
+    keywords: [ "0", "numbers", "blue-square", "null" ],
+    "char": "0\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  one: {
+    keywords: [ "blue-square", "numbers", "1" ],
+    "char": "1\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  two: {
+    keywords: [ "numbers", "2", "prime", "blue-square" ],
+    "char": "2\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  three: {
+    keywords: [ "3", "numbers", "prime", "blue-square" ],
+    "char": "3\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  four: {
+    keywords: [ "4", "numbers", "blue-square" ],
+    "char": "4\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  five: {
+    keywords: [ "5", "numbers", "blue-square", "prime" ],
+    "char": "5\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  six: {
+    keywords: [ "6", "numbers", "blue-square" ],
+    "char": "6\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  seven: {
+    keywords: [ "7", "numbers", "blue-square", "prime" ],
+    "char": "7\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eight: {
+    keywords: [ "8", "blue-square", "numbers" ],
+    "char": "8\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  nine: {
+    keywords: [ "blue-square", "numbers", "9" ],
+    "char": "9\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  keycap_ten: {
+    keywords: [ "numbers", "10", "blue-square" ],
+    "char": "\ud83d\udd1f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  asterisk: {
+    keywords: [ "star", "keycap" ],
+    "char": "*\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  1234: {
+    keywords: [ "numbers", "blue-square" ],
+    "char": "\ud83d\udd22",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  eject_button: {
+    keywords: [ "blue-square" ],
+    "char": "\u23cf\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_forward: {
+    keywords: [ "blue-square", "right", "direction", "play" ],
+    "char": "\u25b6\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  pause_button: {
+    keywords: [ "pause", "blue-square" ],
+    "char": "\u23f8",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  next_track_button: {
+    keywords: [ "forward", "next", "blue-square" ],
+    "char": "\u23ed",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  stop_button: {
+    keywords: [ "blue-square" ],
+    "char": "\u23f9",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  record_button: {
+    keywords: [ "blue-square" ],
+    "char": "\u23fa",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  play_or_pause_button: {
+    keywords: [ "blue-square", "play", "pause" ],
+    "char": "\u23ef",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  previous_track_button: {
+    keywords: [ "backward" ],
+    "char": "\u23ee",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  fast_forward: {
+    keywords: [ "blue-square", "play", "speed", "continue" ],
+    "char": "\u23e9",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  rewind: {
+    keywords: [ "play", "blue-square" ],
+    "char": "\u23ea",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  twisted_rightwards_arrows: {
+    keywords: [ "blue-square", "shuffle", "music", "random" ],
+    "char": "\ud83d\udd00",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  repeat: {
+    keywords: [ "loop", "record" ],
+    "char": "\ud83d\udd01",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  repeat_one: {
+    keywords: [ "blue-square", "loop" ],
+    "char": "\ud83d\udd02",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_backward: {
+    keywords: [ "blue-square", "left", "direction" ],
+    "char": "\u25c0\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up_small: {
+    keywords: [ "blue-square", "triangle", "direction", "point", "forward", "top" ],
+    "char": "\ud83d\udd3c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_down_small: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": "\ud83d\udd3d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_double_up: {
+    keywords: [ "blue-square", "direction", "top" ],
+    "char": "\u23eb",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_double_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": "\u23ec",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_right: {
+    keywords: [ "blue-square", "next" ],
+    "char": "\u27a1\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_left: {
+    keywords: [ "blue-square", "previous", "back" ],
+    "char": "\u2b05\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up: {
+    keywords: [ "blue-square", "continue", "top", "direction" ],
+    "char": "\u2b06\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": "\u2b07\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_upper_right: {
+    keywords: [ "blue-square", "point", "direction", "diagonal", "northeast" ],
+    "char": "\u2197\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_lower_right: {
+    keywords: [ "blue-square", "direction", "diagonal", "southeast" ],
+    "char": "\u2198\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_lower_left: {
+    keywords: [ "blue-square", "direction", "diagonal", "southwest" ],
+    "char": "\u2199\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_upper_left: {
+    keywords: [ "blue-square", "point", "direction", "diagonal", "northwest" ],
+    "char": "\u2196\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_up_down: {
+    keywords: [ "blue-square", "direction", "way", "vertical" ],
+    "char": "\u2195\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_right_arrow: {
+    keywords: [ "shape", "direction", "horizontal", "sideways" ],
+    "char": "\u2194\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrows_counterclockwise: {
+    keywords: [ "blue-square", "sync", "cycle" ],
+    "char": "\ud83d\udd04",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_right_hook: {
+    keywords: [ "blue-square", "return", "rotate", "direction" ],
+    "char": "\u21aa\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  leftwards_arrow_with_hook: {
+    keywords: [ "back", "return", "blue-square", "undo", "enter" ],
+    "char": "\u21a9\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_heading_up: {
+    keywords: [ "blue-square", "direction", "top" ],
+    "char": "\u2934\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrow_heading_down: {
+    keywords: [ "blue-square", "direction", "bottom" ],
+    "char": "\u2935\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hash: {
+    keywords: [ "symbol", "blue-square", "twitter" ],
+    "char": "#\ufe0f\u20e3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  information_source: {
+    keywords: [ "blue-square", "alphabet", "letter" ],
+    "char": "\u2139\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  abc: {
+    keywords: [ "blue-square", "alphabet" ],
+    "char": "\ud83d\udd24",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  abcd: {
+    keywords: [ "blue-square", "alphabet" ],
+    "char": "\ud83d\udd21",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  capital_abcd: {
+    keywords: [ "alphabet", "words", "blue-square" ],
+    "char": "\ud83d\udd20",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  symbols: {
+    keywords: [ "blue-square", "music", "note", "ampersand", "percent", "glyphs", "characters" ],
+    "char": "\ud83d\udd23",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  musical_note: {
+    keywords: [ "score", "tone", "sound" ],
+    "char": "\ud83c\udfb5",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  notes: {
+    keywords: [ "music", "score" ],
+    "char": "\ud83c\udfb6",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  wavy_dash: {
+    keywords: [ "draw", "line", "moustache", "mustache", "squiggle", "scribble" ],
+    "char": "\u3030\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  curly_loop: {
+    keywords: [ "scribble", "draw", "shape", "squiggle" ],
+    "char": "\u27b0",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_check_mark: {
+    keywords: [ "ok", "nike", "answer", "yes", "tick" ],
+    "char": "\u2714\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  arrows_clockwise: {
+    keywords: [ "sync", "cycle", "round", "repeat" ],
+    "char": "\ud83d\udd03",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_plus_sign: {
+    keywords: [ "math", "calculation", "addition", "more", "increase" ],
+    "char": "\u2795",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_minus_sign: {
+    keywords: [ "math", "calculation", "subtract", "less" ],
+    "char": "\u2796",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_division_sign: {
+    keywords: [ "divide", "math", "calculation" ],
+    "char": "\u2797",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_multiplication_x: {
+    keywords: [ "math", "calculation" ],
+    "char": "\u2716\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  infinity: {
+    keywords: [ "forever" ],
+    "char": "\u267e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  heavy_dollar_sign: {
+    keywords: [ "money", "sales", "payment", "currency", "buck" ],
+    "char": "\ud83d\udcb2",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  currency_exchange: {
+    keywords: [ "money", "sales", "dollar", "travel" ],
+    "char": "\ud83d\udcb1",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  copyright: {
+    keywords: [ "ip", "license", "circle", "law", "legal" ],
+    "char": "\xa9\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  registered: {
+    keywords: [ "alphabet", "circle" ],
+    "char": "\xae\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  tm: {
+    keywords: [ "trademark", "brand", "law", "legal" ],
+    "char": "\u2122\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  end: {
+    keywords: [ "words", "arrow" ],
+    "char": "\ud83d\udd1a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  back: {
+    keywords: [ "arrow", "words", "return" ],
+    "char": "\ud83d\udd19",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  on: {
+    keywords: [ "arrow", "words" ],
+    "char": "\ud83d\udd1b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  top: {
+    keywords: [ "words", "blue-square" ],
+    "char": "\ud83d\udd1d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  soon: {
+    keywords: [ "arrow", "words" ],
+    "char": "\ud83d\udd1c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  ballot_box_with_check: {
+    keywords: [ "ok", "agree", "confirm", "black-square", "vote", "election", "yes", "tick" ],
+    "char": "\u2611\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  radio_button: {
+    keywords: [ "input", "old", "music", "circle" ],
+    "char": "\ud83d\udd18",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_circle: {
+    keywords: [ "shape", "round" ],
+    "char": "\u26aa",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_circle: {
+    keywords: [ "shape", "button", "round" ],
+    "char": "\u26ab",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  red_circle: {
+    keywords: [ "shape", "error", "danger" ],
+    "char": "\ud83d\udd34",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_blue_circle: {
+    keywords: [ "shape", "icon", "button" ],
+    "char": "\ud83d\udd35",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_orange_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": "\ud83d\udd38",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_blue_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": "\ud83d\udd39",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_orange_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": "\ud83d\udd36",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  large_blue_diamond: {
+    keywords: [ "shape", "jewel", "gem" ],
+    "char": "\ud83d\udd37",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_red_triangle: {
+    keywords: [ "shape", "direction", "up", "top" ],
+    "char": "\ud83d\udd3a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_small_square: {
+    keywords: [ "shape", "icon" ],
+    "char": "\u25aa\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_small_square: {
+    keywords: [ "shape", "icon" ],
+    "char": "\u25ab\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_large_square: {
+    keywords: [ "shape", "icon", "button" ],
+    "char": "\u2b1b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_large_square: {
+    keywords: [ "shape", "icon", "stone", "button" ],
+    "char": "\u2b1c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  small_red_triangle_down: {
+    keywords: [ "shape", "direction", "bottom" ],
+    "char": "\ud83d\udd3b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_medium_square: {
+    keywords: [ "shape", "button", "icon" ],
+    "char": "\u25fc\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_medium_square: {
+    keywords: [ "shape", "stone", "icon" ],
+    "char": "\u25fb\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_medium_small_square: {
+    keywords: [ "icon", "shape", "button" ],
+    "char": "\u25fe",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_medium_small_square: {
+    keywords: [ "shape", "stone", "icon", "button" ],
+    "char": "\u25fd",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_square_button: {
+    keywords: [ "shape", "input", "frame" ],
+    "char": "\ud83d\udd32",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  white_square_button: {
+    keywords: [ "shape", "input" ],
+    "char": "\ud83d\udd33",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  speaker: {
+    keywords: [ "sound", "volume", "silence", "broadcast" ],
+    "char": "\ud83d\udd08",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  sound: {
+    keywords: [ "volume", "speaker", "broadcast" ],
+    "char": "\ud83d\udd09",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loud_sound: {
+    keywords: [ "volume", "noise", "noisy", "speaker", "broadcast" ],
+    "char": "\ud83d\udd0a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mute: {
+    keywords: [ "sound", "volume", "silence", "quiet" ],
+    "char": "\ud83d\udd07",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mega: {
+    keywords: [ "sound", "speaker", "volume" ],
+    "char": "\ud83d\udce3",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  loudspeaker: {
+    keywords: [ "volume", "sound" ],
+    "char": "\ud83d\udce2",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  bell: {
+    keywords: [ "sound", "notification", "christmas", "xmas", "chime" ],
+    "char": "\ud83d\udd14",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  no_bell: {
+    keywords: [ "sound", "volume", "mute", "quiet", "silent" ],
+    "char": "\ud83d\udd15",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  black_joker: {
+    keywords: [ "poker", "cards", "game", "play", "magic" ],
+    "char": "\ud83c\udccf",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  mahjong: {
+    keywords: [ "game", "play", "chinese", "kanji" ],
+    "char": "\ud83c\udc04",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  spades: {
+    keywords: [ "poker", "cards", "suits", "magic" ],
+    "char": "\u2660\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clubs: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": "\u2663\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  hearts: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": "\u2665\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  diamonds: {
+    keywords: [ "poker", "cards", "magic", "suits" ],
+    "char": "\u2666\ufe0f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  flower_playing_cards: {
+    keywords: [ "game", "sunset", "red" ],
+    "char": "\ud83c\udfb4",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  thought_balloon: {
+    keywords: [ "bubble", "cloud", "speech", "thinking", "dream" ],
+    "char": "\ud83d\udcad",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  right_anger_bubble: {
+    keywords: [ "caption", "speech", "thinking", "mad" ],
+    "char": "\ud83d\uddef",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  speech_balloon: {
+    keywords: [ "bubble", "words", "message", "talk", "chatting" ],
+    "char": "\ud83d\udcac",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  left_speech_bubble: {
+    keywords: [ "words", "message", "talk", "chatting" ],
+    "char": "\ud83d\udde8",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd50",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock2: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd51",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock3: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd52",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock4: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd53",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock5: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd54",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock6: {
+    keywords: [ "time", "late", "early", "schedule", "dawn", "dusk" ],
+    "char": "\ud83d\udd55",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock7: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd56",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock8: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd57",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock9: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd58",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock10: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd59",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock11: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5a",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock12: {
+    keywords: [ "time", "noon", "midnight", "midday", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5b",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock130: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5c",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock230: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5d",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock330: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5e",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock430: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd5f",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock530: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd60",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock630: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd61",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock730: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd62",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock830: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd63",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock930: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd64",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1030: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd65",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1130: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd66",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  clock1230: {
+    keywords: [ "time", "late", "early", "schedule" ],
+    "char": "\ud83d\udd67",
+    fitzpatrick_scale: false,
+    category: "symbols"
+  },
+  afghanistan: {
+    keywords: [ "af", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  aland_islands: {
+    keywords: [ "\xc5land", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddfd",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  albania: {
+    keywords: [ "al", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  algeria: {
+    keywords: [ "dz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  american_samoa: {
+    keywords: [ "american", "ws", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  andorra: {
+    keywords: [ "ad", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  angola: {
+    keywords: [ "ao", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  anguilla: {
+    keywords: [ "ai", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  antarctica: {
+    keywords: [ "aq", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  antigua_barbuda: {
+    keywords: [ "antigua", "barbuda", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  argentina: {
+    keywords: [ "ar", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  armenia: {
+    keywords: [ "am", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  aruba: {
+    keywords: [ "aw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  australia: {
+    keywords: [ "au", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  austria: {
+    keywords: [ "at", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  azerbaijan: {
+    keywords: [ "az", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bahamas: {
+    keywords: [ "bs", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bahrain: {
+    keywords: [ "bh", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bangladesh: {
+    keywords: [ "bd", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  barbados: {
+    keywords: [ "bb", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\udde7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belarus: {
+    keywords: [ "by", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belgium: {
+    keywords: [ "be", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  belize: {
+    keywords: [ "bz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  benin: {
+    keywords: [ "bj", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddef",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bermuda: {
+    keywords: [ "bm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bhutan: {
+    keywords: [ "bt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bolivia: {
+    keywords: [ "bo", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  caribbean_netherlands: {
+    keywords: [ "bonaire", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bosnia_herzegovina: {
+    keywords: [ "bosnia", "herzegovina", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  botswana: {
+    keywords: [ "bw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  brazil: {
+    keywords: [ "br", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  british_indian_ocean_territory: {
+    keywords: [ "british", "indian", "ocean", "territory", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  british_virgin_islands: {
+    keywords: [ "british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  brunei: {
+    keywords: [ "bn", "darussalam", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  bulgaria: {
+    keywords: [ "bg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  burkina_faso: {
+    keywords: [ "burkina", "faso", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  burundi: {
+    keywords: [ "bi", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cape_verde: {
+    keywords: [ "cabo", "verde", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddfb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cambodia: {
+    keywords: [ "kh", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cameroon: {
+    keywords: [ "cm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  canada: {
+    keywords: [ "ca", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  canary_islands: {
+    keywords: [ "canary", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cayman_islands: {
+    keywords: [ "cayman", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  central_african_republic: {
+    keywords: [ "central", "african", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  chad: {
+    keywords: [ "td", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  chile: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cn: {
+    keywords: [ "china", "chinese", "prc", "flag", "country", "nation", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  christmas_island: {
+    keywords: [ "christmas", "island", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddfd",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cocos_islands: {
+    keywords: [ "cocos", "keeling", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  colombia: {
+    keywords: [ "co", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  comoros: {
+    keywords: [ "km", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  congo_brazzaville: {
+    keywords: [ "congo", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  congo_kinshasa: {
+    keywords: [ "congo", "democratic", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cook_islands: {
+    keywords: [ "cook", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  costa_rica: {
+    keywords: [ "costa", "rica", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  croatia: {
+    keywords: [ "hr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udded\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cuba: {
+    keywords: [ "cu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  curacao: {
+    keywords: [ "cura\xe7ao", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cyprus: {
+    keywords: [ "cy", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  czech_republic: {
+    keywords: [ "cz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  denmark: {
+    keywords: [ "dk", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  djibouti: {
+    keywords: [ "dj", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddef",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  dominica: {
+    keywords: [ "dm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  dominican_republic: {
+    keywords: [ "dominican", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ecuador: {
+    keywords: [ "ec", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  egypt: {
+    keywords: [ "eg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  el_salvador: {
+    keywords: [ "el", "salvador", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddfb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  equatorial_guinea: {
+    keywords: [ "equatorial", "gn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  eritrea: {
+    keywords: [ "er", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  estonia: {
+    keywords: [ "ee", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ethiopia: {
+    keywords: [ "et", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  eu: {
+    keywords: [ "european", "union", "flag", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  falkland_islands: {
+    keywords: [ "falkland", "islands", "malvinas", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddeb\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  faroe_islands: {
+    keywords: [ "faroe", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddeb\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  fiji: {
+    keywords: [ "fj", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddeb\ud83c\uddef",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  finland: {
+    keywords: [ "fi", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddeb\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  fr: {
+    keywords: [ "banner", "flag", "nation", "france", "french", "country" ],
+    "char": "\ud83c\uddeb\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_guiana: {
+    keywords: [ "french", "guiana", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_polynesia: {
+    keywords: [ "french", "polynesia", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  french_southern_territories: {
+    keywords: [ "french", "southern", "territories", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gabon: {
+    keywords: [ "ga", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gambia: {
+    keywords: [ "gm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  georgia: {
+    keywords: [ "ge", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  de: {
+    keywords: [ "german", "nation", "flag", "country", "banner" ],
+    "char": "\ud83c\udde9\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ghana: {
+    keywords: [ "gh", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  gibraltar: {
+    keywords: [ "gi", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  greece: {
+    keywords: [ "gr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  greenland: {
+    keywords: [ "gl", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  grenada: {
+    keywords: [ "gd", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guadeloupe: {
+    keywords: [ "gp", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf5",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guam: {
+    keywords: [ "gu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guatemala: {
+    keywords: [ "gt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guernsey: {
+    keywords: [ "gg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guinea: {
+    keywords: [ "gn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guinea_bissau: {
+    keywords: [ "gw", "bissau", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  guyana: {
+    keywords: [ "gy", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  haiti: {
+    keywords: [ "ht", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udded\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  honduras: {
+    keywords: [ "hn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udded\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  hong_kong: {
+    keywords: [ "hong", "kong", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udded\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  hungary: {
+    keywords: [ "hu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udded\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iceland: {
+    keywords: [ "is", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  india: {
+    keywords: [ "in", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  indonesia: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iran: {
+    keywords: [ "iran,", "islamic", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  iraq: {
+    keywords: [ "iq", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ireland: {
+    keywords: [ "ie", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  isle_of_man: {
+    keywords: [ "isle", "man", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  israel: {
+    keywords: [ "il", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  it: {
+    keywords: [ "italy", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddee\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  cote_divoire: {
+    keywords: [ "ivory", "coast", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jamaica: {
+    keywords: [ "jm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddef\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jp: {
+    keywords: [ "japanese", "nation", "flag", "country", "banner" ],
+    "char": "\ud83c\uddef\ud83c\uddf5",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jersey: {
+    keywords: [ "je", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddef\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  jordan: {
+    keywords: [ "jo", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddef\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kazakhstan: {
+    keywords: [ "kz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kenya: {
+    keywords: [ "ke", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kiribati: {
+    keywords: [ "ki", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kosovo: {
+    keywords: [ "xk", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfd\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kuwait: {
+    keywords: [ "kw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kyrgyzstan: {
+    keywords: [ "kg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  laos: {
+    keywords: [ "lao", "democratic", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  latvia: {
+    keywords: [ "lv", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddfb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lebanon: {
+    keywords: [ "lb", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\udde7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lesotho: {
+    keywords: [ "ls", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  liberia: {
+    keywords: [ "lr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  libya: {
+    keywords: [ "ly", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  liechtenstein: {
+    keywords: [ "li", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  lithuania: {
+    keywords: [ "lt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  luxembourg: {
+    keywords: [ "lu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  macau: {
+    keywords: [ "macao", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  macedonia: {
+    keywords: [ "macedonia,", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  madagascar: {
+    keywords: [ "mg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malawi: {
+    keywords: [ "mw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malaysia: {
+    keywords: [ "my", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  maldives: {
+    keywords: [ "mv", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddfb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mali: {
+    keywords: [ "ml", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  malta: {
+    keywords: [ "mt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  marshall_islands: {
+    keywords: [ "marshall", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  martinique: {
+    keywords: [ "mq", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mauritania: {
+    keywords: [ "mr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mauritius: {
+    keywords: [ "mu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mayotte: {
+    keywords: [ "yt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfe\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mexico: {
+    keywords: [ "mx", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddfd",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  micronesia: {
+    keywords: [ "micronesia,", "federated", "states", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddeb\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  moldova: {
+    keywords: [ "moldova,", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  monaco: {
+    keywords: [ "mc", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mongolia: {
+    keywords: [ "mn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  montenegro: {
+    keywords: [ "me", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  montserrat: {
+    keywords: [ "ms", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  morocco: {
+    keywords: [ "ma", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  mozambique: {
+    keywords: [ "mz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  myanmar: {
+    keywords: [ "mm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  namibia: {
+    keywords: [ "na", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nauru: {
+    keywords: [ "nr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nepal: {
+    keywords: [ "np", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddf5",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  netherlands: {
+    keywords: [ "nl", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  new_caledonia: {
+    keywords: [ "new", "caledonia", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  new_zealand: {
+    keywords: [ "new", "zealand", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nicaragua: {
+    keywords: [ "ni", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  niger: {
+    keywords: [ "ne", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  nigeria: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  niue: {
+    keywords: [ "nu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  norfolk_island: {
+    keywords: [ "norfolk", "island", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  northern_mariana_islands: {
+    keywords: [ "northern", "mariana", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf2\ud83c\uddf5",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  north_korea: {
+    keywords: [ "north", "korea", "nation", "flag", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddf5",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  norway: {
+    keywords: [ "no", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf3\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  oman: {
+    keywords: [ "om_symbol", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf4\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pakistan: {
+    keywords: [ "pk", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  palau: {
+    keywords: [ "pw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  palestinian_territories: {
+    keywords: [ "palestine", "palestinian", "territories", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  panama: {
+    keywords: [ "pa", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  papua_new_guinea: {
+    keywords: [ "papua", "new", "guinea", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  paraguay: {
+    keywords: [ "py", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  peru: {
+    keywords: [ "pe", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  philippines: {
+    keywords: [ "ph", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pitcairn_islands: {
+    keywords: [ "pitcairn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  poland: {
+    keywords: [ "pl", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  portugal: {
+    keywords: [ "pt", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  puerto_rico: {
+    keywords: [ "puerto", "rico", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  qatar: {
+    keywords: [ "qa", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf6\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  reunion: {
+    keywords: [ "r\xe9union", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf7\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  romania: {
+    keywords: [ "ro", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf7\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ru: {
+    keywords: [ "russian", "federation", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf7\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  rwanda: {
+    keywords: [ "rw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf7\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_barthelemy: {
+    keywords: [ "saint", "barth\xe9lemy", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde7\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_helena: {
+    keywords: [ "saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_kitts_nevis: {
+    keywords: [ "saint", "kitts", "nevis", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_lucia: {
+    keywords: [ "saint", "lucia", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_pierre_miquelon: {
+    keywords: [ "saint", "pierre", "miquelon", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf5\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  st_vincent_grenadines: {
+    keywords: [ "saint", "vincent", "grenadines", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  samoa: {
+    keywords: [ "ws", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfc\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  san_marino: {
+    keywords: [ "san", "marino", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sao_tome_principe: {
+    keywords: [ "sao", "tome", "principe", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  saudi_arabia: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  senegal: {
+    keywords: [ "sn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  serbia: {
+    keywords: [ "rs", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf7\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  seychelles: {
+    keywords: [ "sc", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sierra_leone: {
+    keywords: [ "sierra", "leone", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  singapore: {
+    keywords: [ "sg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sint_maarten: {
+    keywords: [ "sint", "maarten", "dutch", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddfd",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  slovakia: {
+    keywords: [ "sk", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  slovenia: {
+    keywords: [ "si", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  solomon_islands: {
+    keywords: [ "solomon", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\udde7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  somalia: {
+    keywords: [ "so", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_africa: {
+    keywords: [ "south", "africa", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddff\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_georgia_south_sandwich_islands: {
+    keywords: [ "south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddec\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  kr: {
+    keywords: [ "south", "korea", "nation", "flag", "country", "banner" ],
+    "char": "\ud83c\uddf0\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  south_sudan: {
+    keywords: [ "south", "sd", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  es: {
+    keywords: [ "spain", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sri_lanka: {
+    keywords: [ "sri", "lanka", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf1\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sudan: {
+    keywords: [ "sd", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\udde9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  suriname: {
+    keywords: [ "sr", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  swaziland: {
+    keywords: [ "sz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  sweden: {
+    keywords: [ "se", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  switzerland: {
+    keywords: [ "ch", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde8\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  syria: {
+    keywords: [ "syrian", "arab", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf8\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  taiwan: {
+    keywords: [ "tw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tajikistan: {
+    keywords: [ "tj", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddef",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tanzania: {
+    keywords: [ "tanzania,", "united", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  thailand: {
+    keywords: [ "th", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  timor_leste: {
+    keywords: [ "timor", "leste", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf1",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  togo: {
+    keywords: [ "tg", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tokelau: {
+    keywords: [ "tk", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf0",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tonga: {
+    keywords: [ "to", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf4",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  trinidad_tobago: {
+    keywords: [ "trinidad", "tobago", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf9",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tunisia: {
+    keywords: [ "tn", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tr: {
+    keywords: [ "turkey", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  turkmenistan: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  turks_caicos_islands: {
+    keywords: [ "turks", "caicos", "islands", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\udde8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  tuvalu: {
+    keywords: [ "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddf9\ud83c\uddfb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uganda: {
+    keywords: [ "ug", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\uddec",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  ukraine: {
+    keywords: [ "ua", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  united_arab_emirates: {
+    keywords: [ "united", "arab", "emirates", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\udde6\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uk: {
+    keywords: [ "united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack" ],
+    "char": "\ud83c\uddec\ud83c\udde7",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  england: {
+    keywords: [ "flag", "english" ],
+    "char": "\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  scotland: {
+    keywords: [ "flag", "scottish" ],
+    "char": "\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  wales: {
+    keywords: [ "flag", "welsh" ],
+    "char": "\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  us: {
+    keywords: [ "united", "states", "america", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\uddf8",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  us_virgin_islands: {
+    keywords: [ "virgin", "islands", "us", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\uddee",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uruguay: {
+    keywords: [ "uy", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\uddfe",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  uzbekistan: {
+    keywords: [ "uz", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\uddff",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vanuatu: {
+    keywords: [ "vu", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\uddfa",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vatican_city: {
+    keywords: [ "vatican", "city", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\udde6",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  venezuela: {
+    keywords: [ "ve", "bolivarian", "republic", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  vietnam: {
+    keywords: [ "viet", "nam", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfb\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  wallis_futuna: {
+    keywords: [ "wallis", "futuna", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfc\ud83c\uddeb",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  western_sahara: {
+    keywords: [ "western", "sahara", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddea\ud83c\udded",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  yemen: {
+    keywords: [ "ye", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddfe\ud83c\uddea",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  zambia: {
+    keywords: [ "zm", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddff\ud83c\uddf2",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  zimbabwe: {
+    keywords: [ "zw", "flag", "nation", "country", "banner" ],
+    "char": "\ud83c\uddff\ud83c\uddfc",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  united_nations: {
+    keywords: [ "un", "flag", "banner" ],
+    "char": "\ud83c\uddfa\ud83c\uddf3",
+    fitzpatrick_scale: false,
+    category: "flags"
+  },
+  pirate_flag: {
+    keywords: [ "skull", "crossbones", "flag", "banner" ],
+    "char": "\ud83c\udff4\u200d\u2620\ufe0f",
+    fitzpatrick_scale: false,
+    category: "flags"
+  }
+});

File diff suppressed because it is too large
+ 1 - 0
public/assets/v1/common/lib/tinymce/plugins/emoticons/js/emojis.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/emoticons/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/fullpage/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/fullscreen/plugin.min.js


+ 52 - 0
public/assets/v1/common/lib/tinymce/plugins/gallery/plugin.js

@@ -0,0 +1,52 @@
+tinymce.PluginManager.add('gallery', function(editor, url) {
+	// 注册一个工具栏按钮名称
+	editor.ui.registry.addButton('gallery', {
+		text: '素材库',
+		onAction: function (e) {
+			$Gallery.GalleryDialogOpen({max:10,size:100,is_new:1,suffix:'bmp,gif,jpg,jpeg,png',type:'1', tabs:true,multiple:true,callback:function (res) {
+					console.log(res.length);
+					if(res.length > 1){
+						$.each(res, function (key, val) {
+							if(parseInt(val.type) === 1){
+								var html='<p><img src="'+val.url+'" alt="'+val.original+'" width="" height="" /></p>';
+								editor.insertContent(html);
+							} else {
+								tinyMCE.activeEditor.setContent(
+									`<p>
+               <span class="mce-preview-object mce-object-video" contenteditable="false" data-mce-object="video" data-mce-p-allowfullscreen="allowfullscreen" data-mce-p-frameborder="no" data-mce-p-scrolling="no" data-mce-html="%20">
+                 <video src=`+val.url+` width="100%" controls="controls"></video>
+               </span>
+            </p>`
+								);
+							}
+						})
+					} else {
+						if(parseInt(res.type) === 1){
+							var html='<p><img src="'+res.url+'" alt="'+res.original+'" width="" height="" /></p>';
+							editor.insertContent(html);
+						} else {
+							tinyMCE.activeEditor.setContent(
+								`<p>
+               <span class="mce-preview-object mce-object-video" contenteditable="false" data-mce-object="video" data-mce-p-allowfullscreen="allowfullscreen" data-mce-p-frameborder="no" data-mce-p-scrolling="no" data-mce-html="%20">
+                 <video src=`+res.url+` width="100%" controls="controls"></video>
+               </span>
+            </p>`
+							);
+						}
+					}
+
+				}});
+		}
+	});
+
+	return {
+		getMetadata: function () {
+			return  {
+				//插件名和链接会显示在“帮助”→“插件”→“已安装的插件”中
+				name: "gallery",//插件名称
+				url: "http://exampleplugindocsurl.com", //作者网址
+			};
+		}
+	};
+});
+

+ 41 - 0
public/assets/v1/common/lib/tinymce/plugins/gallery/plugin.min.js

@@ -0,0 +1,41 @@
+tinymce.PluginManager.add('gallery', function (editor, url) {
+    // 注册一个工具栏按钮名称
+    editor.ui.registry.addButton('gallery', {
+        text: '素材库',
+        onAction: function (e) {
+            $Gallery.GalleryDialogOpen({
+                max: 10,
+                size: 100,
+                is_new: 1,
+                suffix: 'bmp,gif,jpg,jpeg,png',
+                type: '1',
+                tabs: true,
+                multiple: true,
+                callback: function (res) {
+
+                    $.each(res, function (key, val) {
+                        if (parseInt(val.type) === 1) {
+                            var html = '<p><img src="' + val.url + '" alt="' + val.original + '" width="" height="" /></p>';
+                            editor.insertContent(html);
+                        } else {
+                            // editor.insertContent(`<video src=` + val.url + ` width="100%" controls="controls"></video>`);
+                            var html = `<p><span class="mce-preview-object mce-object-video" contenteditable="false" data-mce-object="video" data-mce-p-allowfullscreen="allowfullscreen" data-mce-p-frameborder="no" data-mce-p-scrolling="no" data-mce-p-src=${val.url} data-mce-html="%20"><video src=${val.url} width="100%" controls="controls"></video></span></p>`;
+                            editor.insertContent(html);
+                        }
+                    })
+                }
+            });
+        }
+    });
+
+    return {
+        getMetadata: function () {
+            return {
+                //插件名和链接会显示在“帮助”→“插件”→“已安装的插件”中
+                name: "gallery",//插件名称
+                url: "http://exampleplugindocsurl.com", //作者网址
+            };
+        }
+    };
+});
+

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/help/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/hr/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");n.add("hr",function(n){var o,t;(o=n).addCommand("InsertHorizontalRule",function(){o.execCommand("mceInsertContent",!1,"<hr />")}),(t=n).ui.registry.addButton("hr",{icon:"horizontal-rule",tooltip:"Horizontal line",onAction:function(){return t.execCommand("InsertHorizontalRule")}}),t.ui.registry.addMenuItem("hr",{icon:"horizontal-rule",text:"Horizontal line",onAction:function(){return t.execCommand("InsertHorizontalRule")}})})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/image/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/imagetools/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/importcss/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/insertdatetime/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/legacyoutput/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/link/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/lists/plugin.min.js


+ 595 - 0
public/assets/v1/common/lib/tinymce/plugins/media/plugin.min.js

@@ -0,0 +1,595 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function () {
+    "use strict";
+    var e, t, r, n = tinymce.util.Tools.resolve("tinymce.PluginManager"), p = function () {
+            return (p = Object.assign || function (e) {
+                for (var t, r = 1, n = arguments.length; r < n; r++) for (var i in t = arguments[r]) Object.prototype.hasOwnProperty.call(t, i) && (e[i] = t[i]);
+                return e
+            }).apply(this, arguments)
+        }, a = function (e) {
+            return function () {
+                return e
+            }
+        }, o = a(!1), c = a(!0), i = function () {
+            return u
+        }, u = (e = function (e) {
+            return e.isNone()
+        }, {
+            fold: function (e, t) {
+                return e()
+            }, is: o, isSome: o, isNone: c, getOr: r = function (e) {
+                return e
+            }, getOrThunk: t = function (e) {
+                return e()
+            }, getOrDie: function (e) {
+                throw new Error(e || "error: getOrDie called on none.")
+            }, getOrNull: a(null), getOrUndefined: a(undefined), or: r, orThunk: t, map: i, each: function () {
+            }, bind: i, exists: o, forall: c, filter: i, equals: e, equals_: e, toArray: function () {
+                return []
+            }, toString: a("none()")
+        }), s = function (r) {
+            var e = a(r), t = function () {
+                return i
+            }, n = function (e) {
+                return e(r)
+            }, i = {
+                fold: function (e, t) {
+                    return t(r)
+                },
+                is: function (e) {
+                    return r === e
+                },
+                isSome: c,
+                isNone: o,
+                getOr: e,
+                getOrThunk: e,
+                getOrDie: e,
+                getOrNull: e,
+                getOrUndefined: e,
+                or: t,
+                orThunk: t,
+                map: function (e) {
+                    return s(e(r))
+                },
+                each: function (e) {
+                    e(r)
+                },
+                bind: n,
+                exists: n,
+                forall: n,
+                filter: function (e) {
+                    return e(r) ? i : u
+                },
+                toArray: function () {
+                    return [r]
+                },
+                toString: function () {
+                    return "some(" + r + ")"
+                },
+                equals: function (e) {
+                    return e.is(r)
+                },
+                equals_: function (e, t) {
+                    return e.fold(o, function (e) {
+                        return t(r, e)
+                    })
+                }
+            };
+            return i
+        }, l = {
+            some: s, none: i, from: function (e) {
+                return null === e || e === undefined ? u : s(e)
+            }
+        }, m = function (n) {
+            return function (e) {
+                return r = typeof (t = e), (null === t ? "null" : "object" == r && (Array.prototype.isPrototypeOf(t) || t.constructor && "Array" === t.constructor.name) ? "array" : "object" == r && (String.prototype.isPrototypeOf(t) || t.constructor && "String" === t.constructor.name) ? "string" : r) === n;
+                var t, r
+            }
+        }, d = m("string"), h = m("object"), g = m("array"), v = Array.prototype.push, f = function (e, t) {
+            for (var r = 0, n = e.length; r < n; r++) {
+                t(e[r], r)
+            }
+        }, w = function (e) {
+            var t = e;
+            return {
+                get: function () {
+                    return t
+                }, set: function (e) {
+                    t = e
+                }
+            }
+        }, b = Object.keys, y = Object.hasOwnProperty, x = function (e, t) {
+            return j(e, t) ? l.from(e[t]) : l.none()
+        }, j = function (e, t) {
+            return y.call(e, t)
+        }, O = function (e) {
+            return e.getParam("media_scripts")
+        }, S = tinymce.util.Tools.resolve("tinymce.util.Tools"), _ = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),
+        k = tinymce.util.Tools.resolve("tinymce.html.SaxParser"), A = function (e, t) {
+            if (e) for (var r = 0; r < e.length; r++) if (-1 !== t.indexOf(e[r].filter)) return e[r]
+        }, T = _.DOM, C = function (e) {
+            return e.replace(/px$/, "")
+        }, P = function (o, e) {
+            var c = w(!1), u = {};
+            return k({
+                validate: !1, allow_conditional_comments: !0, start: function (e, t) {
+                    if (!c.get()) if (j(t.map, "data-ephox-embed-iri")) c.set(!0), i = (n = t).map.style, a = i ? T.parseStyle(i) : {}, u = {
+                        type: "ephox-embed-iri",
+                        source: n.map["data-ephox-embed-iri"],
+                        altsource: "",
+                        poster: "",
+                        width: x(a, "max-width").map(C).getOr(""),
+                        height: x(a, "max-height").map(C).getOr("")
+                    }; else {
+                        if (u.source || "param" !== e || (u.source = t.map.movie), "iframe" !== e && "object" !== e && "embed" !== e && "video" !== e && "audio" !== e || (u.type || (u.type = e), u = S.extend(t.map, u)), "script" === e) {
+                            var r = A(o, t.map.src);
+                            if (!r) return;
+                            u = {type: "script", source: t.map.src, width: String(r.width), height: String(r.height)}
+                        }
+                        "source" === e && (u.source ? u.altsource || (u.altsource = t.map.src) : u.source = t.map.src), "img" !== e || u.poster || (u.poster = t.map.src)
+                    }
+                    var n, i, a
+                }
+            }).parse(e), u.source = u.source || u.src || u.data, u.altsource = u.altsource || "", u.poster = u.poster || "", u
+        }, D = function (e) {
+            var t = {
+                mp3: "audio/mpeg",
+                m4a: "audio/x-m4a",
+                wav: "audio/wav",
+                mp4: "video/mp4",
+                webm: "video/webm",
+                ogg: "video/ogg",
+                swf: "application/x-shockwave-flash"
+            }[e.toLowerCase().split(".").pop()];
+            return t || ""
+        }, $ = tinymce.util.Tools.resolve("tinymce.html.Schema"), F = tinymce.util.Tools.resolve("tinymce.html.Writer"),
+        M = _.DOM, z = function (e) {
+            return /^[0-9.]+$/.test(e) ? e + "px" : e
+        }, N = function (a, e) {
+            !function (e, t) {
+                for (var r = b(e), n = 0, i = r.length; n < i; n++) {
+                    var a = r[n];
+                    t(e[a], a)
+                }
+            }(e, function (e, t) {
+                var r = "" + e;
+                if (a.map[t]) for (var n = a.length; n--;) {
+                    var i = a[n];
+                    i.name === t && (r ? (a.map[t] = r, i.value = r) : (delete a.map[t], a.splice(n, 1)))
+                } else r && (a.push({name: t, value: r}), a.map[t] = r)
+            })
+        }, U = ["source", "altsource"], E = function (e, c, u) {
+            var s, l = F(), m = w(!1), d = 0;
+            return k({
+                validate: !1, allow_conditional_comments: !0, comment: function (e) {
+                    l.comment(e)
+                }, cdata: function (e) {
+                    l.cdata(e)
+                }, text: function (e, t) {
+                    l.text(e, t)
+                }, start: function (e, t, r) {
+                    if (!m.get()) if (j(t.map, "data-ephox-embed-iri")) m.set(!0), n = c, a = (i = t).map.style, (o = a ? M.parseStyle(a) : {})["max-width"] = z(n.width), o["max-height"] = z(n.height), N(i, {style: M.serializeStyle(o)}); else {
+                        switch (e) {
+                            case"video":
+                            case"object":
+                            case"embed":
+                            case"img":
+                            case"iframe":
+                                c.height !== undefined && c.width !== undefined && N(t, {width: c.width, height: c.height})
+                        }
+                        if (u) switch (e) {
+                            case"video":
+                                N(t, {poster: c.poster, src: ""}), c.altsource && N(t, {src: ""});
+                                break;
+                            case"iframe":
+                                N(t, {src: c.source});
+                                break;
+                            case"source":
+                                if (d < 2 && (N(t, {src: c[U[d]], type: c[U[d] + "mime"]}), !c[U[d]])) return;
+                                d++;
+                                break;
+                            case"img":
+                                if (!c.poster) return;
+                                s = !0
+                        }
+                    }
+                    var n, i, a, o;
+                    l.start(e, t, r)
+                }, end: function (e) {
+                    if (!m.get()) {
+                        if ("video" === e && u) for (var t, r = 0; r < 2; r++) {
+                            c[U[r]] && ((t = []).map = {}, d <= r && (N(t, {
+                                src: c[U[r]],
+                                type: c[U[r] + "mime"]
+                            }), l.start("source", t, !0)))
+                        }
+                        var n;
+                        c.poster && "object" === e && u && !s && ((n = []).map = {}, N(n, {
+                            src: c.poster,
+                            width: c.width,
+                            height: c.height
+                        }), l.start("img", n, !0))
+                    }
+                    l.end(e)
+                }
+            }, $({})).parse(e), l.getContent()
+        }, R = [{
+            regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
+            type: "iframe",
+            w: 560,
+            h: 314,
+            url: "www.youtube.com/embed/$1",
+            allowFullscreen: !0
+        }, {
+            regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
+            type: "iframe",
+            w: 560,
+            h: 314,
+            url: "www.youtube.com/embed/$2?$4",
+            allowFullscreen: !0
+        }, {
+            regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
+            type: "iframe",
+            w: 560,
+            h: 314,
+            url: "www.youtube.com/embed/$1",
+            allowFullscreen: !0
+        }, {
+            regex: /vimeo\.com\/([0-9]+)/,
+            type: "iframe",
+            w: 425,
+            h: 350,
+            url: "player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",
+            allowFullscreen: !0
+        }, {
+            regex: /vimeo\.com\/(.*)\/([0-9]+)/,
+            type: "iframe",
+            w: 425,
+            h: 350,
+            url: "player.vimeo.com/video/$2?title=0&amp;byline=0",
+            allowFullscreen: !0
+        }, {
+            regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
+            type: "iframe",
+            w: 425,
+            h: 350,
+            url: 'maps.google.com/maps/ms?msid=$2&output=embed"',
+            allowFullscreen: !1
+        }, {
+            regex: /dailymotion\.com\/video\/([^_]+)/,
+            type: "iframe",
+            w: 480,
+            h: 270,
+            url: "www.dailymotion.com/embed/video/$1",
+            allowFullscreen: !0
+        }, {
+            regex: /dai\.ly\/([^_]+)/,
+            type: "iframe",
+            w: 480,
+            h: 270,
+            url: "www.dailymotion.com/embed/video/$1",
+            allowFullscreen: !0
+        }], L = function (t) {
+            var e = R.filter(function (e) {
+                return e.regex.test(t)
+            });
+            return 0 < e.length ? S.extend({}, e[0], {
+                url: function (e, t) {
+                    for (var r, n = (r = t.match(/^(https?:\/\/|www\.)(.+)$/i)) && 1 < r.length && "www." !== r[1] ? r[1] : "https://", i = e.regex.exec(t), a = n + e.url, o = 0; o < i.length; o++) !function (e) {
+                        a = a.replace("$" + e, function () {
+                            return i[e] ? i[e] : ""
+                        })
+                    }(o);
+                    return a.replace(/\?$/, "")
+                }(e[0], t)
+            }) : null
+        }, I = function (r, e) {
+            var n = S.extend({}, e);
+            if (!n.source && (S.extend(n, P(O(r), n.embed)), !n.source)) return "";
+            n.altsource || (n.altsource = ""), n.poster || (n.poster = ""), n.source = r.convertURL(n.source, "source"), n.altsource = r.convertURL(n.altsource, "source"), n.sourcemime = D(n.source), n.altsourcemime = D(n.altsource), n.poster = r.convertURL(n.poster, "poster");
+            var t = L(n.source);
+            if (t && (n.source = t.url, n.type = t.type, n.allowFullscreen = t.allowFullscreen, n.width = n.width || String(t.w), n.height = n.height || String(t.h)), n.embed) return E(n.embed, n, !0);
+            var i = A(O(r), n.source);
+            i && (n.type = "script", n.width = String(i.width), n.height = String(i.height));
+            var a, o, c, u, s, l, m, d, h = r.getParam("audio_template_callback"),
+                f = r.getParam("video_template_callback");
+            return n.width = n.width || "300", n.height = n.height || "150", S.each(n, function (e, t) {
+                n[t] = r.dom.encode("" + e)
+            }), "iframe" === n.type ? (d = (m = n).allowFullscreen ? ' allowFullscreen="1"' : "", '<iframe src="' + m.source + '" width="' + m.width + '" height="' + m.height + '"' + d + "></iframe>") : "application/x-shockwave-flash" === n.sourcemime ? (l = '<object data="' + (s = n).source + '" width="' + s.width + '" height="' + s.height + '" type="application/x-shockwave-flash">', s.poster && (l += '<img src="' + s.poster + '" width="' + s.width + '" height="' + s.height + '" />'), l += "</object>") : -1 !== n.sourcemime.indexOf("audio") ? (c = n, (u = h) ? u(c) : '<audio controls="controls" src="' + c.source + '">' + (c.altsource ? '\n<source src="' + c.altsource + '"' + (c.altsourcemime ? ' type="' + c.altsourcemime + '"' : "") + " />\n" : "") + "</audio>") : "script" === n.type ? '<script src="' + n.source + '"><\/script>' : (a = n, (o = f) ? o(a) : '<video width="' + a.width + '" height="' + a.height + '"' + (a.poster ? ' poster="' + a.poster + '"' : "") + ' controls="controls">\n<source src="' + a.source + '"' + (a.sourcemime ? ' type="' + a.sourcemime + '"' : "") + " />\n" + (a.altsource ? '<source src="' + a.altsource + '"' + (a.altsourcemime ? ' type="' + a.altsourcemime + '"' : "") + " />\n" : "") + "</video>")
+        }, q = tinymce.util.Tools.resolve("tinymce.util.Promise"), B = {}, W = function (t) {
+            return function (e) {
+                return I(t, e)
+            }
+        }, G = function (e, t) {
+            var r, n, i, a, o, c = e.getParam("media_url_resolver");
+            return c ? (i = t, a = W(e), o = c, new q(function (t, e) {
+                var r = function (e) {
+                    return e.html && (B[i.source] = e), t({url: i.source, html: e.html ? e.html : a(i)})
+                };
+                B[i.source] ? r(B[i.source]) : o({url: i.source}, r, e)
+            })) : (r = t, n = W(e), new q(function (e) {
+                e({html: n(r), url: r.source})
+            }))
+        }, H = function (a, o, c) {
+            return function (e) {
+                var t = function () {
+                    return x(a, e)
+                }, r = function () {
+                    return x(o, e)
+                }, n = function (e) {
+                    return x(e, "value").bind(function (e) {
+                        return 0 < e.length ? l.some(e) : l.none()
+                    })
+                }, i = {};
+                return i[e] = (e === c ? t().bind(function (e) {
+                    return h(e) ? n(e).orThunk(r) : r().orThunk(function () {
+                        return l.from(e)
+                    })
+                }) : r().orThunk(function () {
+                    return t().bind(function (e) {
+                        return h(e) ? n(e) : l.from(e)
+                    })
+                })).getOr(""), i
+            }
+        }, J = function (e, t) {
+            var r, n, i = t ? x(e, t).bind(function (e) {
+                return x(e, "meta")
+            }).getOr({}) : {}, a = H(e, i, t);
+            return p(p(p(p(p({}, a("source")), a("altsource")), a("poster")), a("embed")), (r = i, n = {}, x(e, "dimensions").each(function (e) {
+                f(["width", "height"], function (t) {
+                    x(r, t).orThunk(function () {
+                        return x(e, t)
+                    }).each(function (e) {
+                        return n[t] = e
+                    })
+                })
+            }), n))
+        }, K = function (e) {
+            var n = p(p({}, e), {
+                source: {value: x(e, "source").getOr("")},
+                altsource: {value: x(e, "altsource").getOr("")},
+                poster: {value: x(e, "poster").getOr("")}
+            });
+            return f(["width", "height"], function (r) {
+                x(e, r).each(function (e) {
+                    var t = n.dimensions || {};
+                    t[r] = e, n.dimensions = t
+                })
+            }), n
+        }, Q = function (r) {
+            return function (e) {
+                var t = e && e.msg ? "Media embed handler error: " + e.msg : "Media embed handler threw unknown error.";
+                r.notificationManager.open({type: "error", text: t})
+            }
+        }, V = function (e, t) {
+            return P(O(e), t)
+        }, X = function (i, a) {
+            return function (e) {
+                var t, r, n;
+                d(e.url) && 0 < e.url.trim().length && (t = e.html, r = V(a, t), n = p(p({}, r), {
+                    source: e.url,
+                    embed: t
+                }), i.setData(K(n)))
+            }
+        }, Y = function (e, t) {
+            var r = e.dom.select("img[data-mce-object]");
+            e.insertContent(t), function (e, t) {
+                for (var r = e.dom.select("img[data-mce-object]"), n = 0; n < t.length; n++) for (var i = r.length - 1; 0 <= i; i--) t[n] === r[i] && r.splice(i, 1);
+                e.selection.select(r[0])
+            }(e, r), e.nodeChanged()
+        }, Z = function (e, t, r) {
+            var n;
+            t.embed = E(t.embed, t), t.embed && (e.source === t.source || (n = t.source, B.hasOwnProperty(n))) ? Y(r, t.embed) : G(r, t).then(function (e) {
+                Y(r, e.html)
+            })["catch"](Q(r))
+        }, ee = function (m) {
+            var e, t, r, n,
+                i = (r = (e = m).selection.getNode(), n = (t = r).getAttribute("data-mce-object") || t.getAttribute("data-ephox-embed-iri") ? e.serializer.serialize(r, {selection: !0}) : "", p({embed: n}, P(O(e), n))),
+                d = w(i), a = K(i), o = {
+                    title: "General", name: "general", items: function (e) {
+                        for (var t = [], r = 0, n = e.length; r < n; ++r) {
+                            if (!g(e[r])) throw new Error("Arr.flatten item " + r + " was not an array, input: " + e);
+                            v.apply(t, e[r])
+                        }
+                        return t
+                    }([[{
+                        name: "source",
+                        type: "urlinput",
+                        filetype: "media",
+                        label: "Source"
+                    }], m.getParam("media_dimensions", !0) ? [{
+                        type: "sizeinput",
+                        name: "dimensions",
+                        label: "Constrain proportions",
+                        constrain: !0
+                    }] : []])
+                }, c = {title: "Embed", items: [{type: "textarea", name: "embed", label: "Paste your embed code below:"}]},
+                u = [];
+            m.getParam("media_alt_source", !0) && u.push({
+                name: "altsource",
+                type: "urlinput",
+                filetype: "media",
+                label: "Alternative source URL"
+            }), m.getParam("media_poster", !0) && u.push({
+                name: "poster",
+                type: "urlinput",
+                filetype: "image",
+                label: "Media poster (Image URL)"
+            });
+            var s = {title: "Advanced", name: "advanced", items: u}, l = [o, c];
+            0 < u.length && l.push(s);
+            var h = {type: "tabpanel", tabs: l}, f = m.windowManager.open({
+                title: "Insert/Edit Media",
+                size: "normal",
+                body: h,
+                buttons: [{type: "cancel", name: "cancel", text: "Cancel"}, {
+                    type: "submit",
+                    name: "save",
+                    text: "Save",
+                    primary: !0
+                }],
+                onSubmit: function (e) {
+                    var t = J(e.getData());
+                    Z(d.get(), t, m), e.close()
+                },
+                onChange: function (e, t) {
+                    switch (t.name) {
+                        case"source":
+                            s = d.get(), l = J(e.getData(), "source"), s.source !== l.source && (X(f, m)({
+                                url: l.source,
+                                html: ""
+                            }), G(m, l).then(X(f, m))["catch"](Q(m)));
+                            break;
+                        case"embed":
+                            c = J((o = e).getData()), u = V(m, c.embed), o.setData(K(u));
+                            break;
+                        case"dimensions":
+                        case"altsource":
+                        case"poster":
+                            r = e, n = t.name, i = J(r.getData(), n), a = I(m, i), r.setData(K(p(p({}, i), {embed: a})))
+                    }
+                    var r, n, i, a, o, c, u, s, l;
+                    d.set(J(e.getData()))
+                },
+                initialData: a
+            })
+        }, te = tinymce.util.Tools.resolve("tinymce.html.Node"), re = tinymce.util.Tools.resolve("tinymce.Env"),
+        ne = function (a, e) {
+            if (!1 === a.getParam("media_filter_html", !0)) return e;
+            var o, c = F();
+            return k({
+                validate: !1, allow_conditional_comments: !1, comment: function (e) {
+                    c.comment(e)
+                }, cdata: function (e) {
+                    c.cdata(e)
+                }, text: function (e, t) {
+                    c.text(e, t)
+                }, start: function (e, t, r) {
+                    if (o = !0, "script" !== e && "noscript" !== e && "svg" !== e) {
+                        for (var n = t.length - 1; 0 <= n; n--) {
+                            var i = t[n].name;
+                            0 === i.indexOf("on") && (delete t.map[i], t.splice(n, 1)), "style" === i && (t[n].value = a.dom.serializeStyle(a.dom.parseStyle(t[n].value), e))
+                        }
+                        c.start(e, t, r), o = !1
+                    }
+                }, end: function (e) {
+                    o || c.end(e)
+                }
+            }, $({})).parse(e), c.getContent()
+        }, ie = function (e, t, r) {
+            for (var n, i, a = t.attributes, o = a.length; o--;) n = a[o].name, i = a[o].value, "width" !== n && "height" !== n && "style" !== n && ("data" !== n && "src" !== n || (i = e.convertURL(i, n)), r.attr("data-mce-p-" + n, i));
+            var c = t.firstChild && t.firstChild.value;
+            c && (r.attr("data-mce-html", escape(ne(e, c))), r.firstChild = null)
+        }, ae = function (e) {
+            for (; e = e.parent;) if (e.attr("data-ephox-embed-iri") || (t = e.attr("class")) && /\btiny-pageembed\b/.test(t)) return !0;
+            var t;
+            return !1
+        }, oe = function (u) {
+            return function (e) {
+                for (var t, r, n, i, a, o, c = e.length; c--;) (t = e[c]).parent && (t.parent.attr("data-mce-object") || "script" === t.name && !(r = A(O(u), t.attr("src"))) || (r && (r.width && t.attr("width", r.width.toString()), r.height && t.attr("height", r.height.toString())), "iframe" === t.name && u.getParam("media_live_embeds", !0) && re.ceFalse ? ae(t) || t.replace(function (e, t) {
+                    var r = t.name, n = new te("span", 1);
+                    n.attr({
+                        contentEditable: "false",
+                        style: t.attr("style"),
+                        "data-mce-object": r,
+                        "class": "mce-preview-object mce-object-" + r
+                    }), ie(e, t, n);
+                    var i = new te(r, 1);
+                    i.attr({
+                        src: t.attr("src"),
+                        allowfullscreen: t.attr("allowfullscreen"),
+                        style: t.attr("style"),
+                        "class": t.attr("class"),
+                        width: t.attr("width"),
+                        height: t.attr("height"),
+                        frameborder: "0"
+                    });
+                    var a = new te("span", 1);
+                    return a.attr("class", "mce-shim"), n.append(i), n.append(a), n
+                }(u, t)) : ae(t) || t.replace((n = u, o = void 0, a = (i = t).name, (o = new te("img", 1)).shortEnded = !0, ie(n, i, o), o.attr({
+                    width: i.attr("width") || "300",
+                    height: i.attr("height") || ("audio" === a ? "30" : "150"),
+                    style: i.attr("style"),
+                    src: re.transparentSrc,
+                    "data-mce-object": a,
+                    "class": "mce-object mce-object-" + a
+                }), o))))
+            }
+        }, ce = function (e) {
+            var t, r;
+            e.ui.registry.addToggleButton("media", {
+                tooltip: "Insert/edit media",
+                icon: "embed",
+                onAction: function () {
+                    e.execCommand("mceMedia")
+                },
+                onSetup: (t = e, r = ["img[data-mce-object]", "span[data-mce-object]", "div[data-ephox-embed-iri]"], function (e) {
+                    return t.selection.selectorChangedWithUnbind(r.join(","), e.setActive).unbind
+                })
+            }), e.ui.registry.addMenuItem("media", {
+                icon: "embed", text: "Media...", onAction: function () {
+                    e.execCommand("mceMedia")
+                }
+            })
+        };
+    n.add("media", function (e) {
+        var t, d, r, n;
+        return (t = e).addCommand("mceMedia", function () {
+            ee(t)
+        }), ce(e), e.on("ResolveName", function (e) {
+            var t;
+            1 === e.target.nodeType && (t = e.target.getAttribute("data-mce-object")) && (e.name = t)
+        }), (d = e).on("preInit", function () {
+            var t = d.schema.getSpecialElements();
+            S.each("video audio iframe object".split(" "), function (e) {
+                t[e] = new RegExp("</" + e + "[^>]*>", "gi")
+            });
+            var r = d.schema.getBoolAttrs();
+            S.each("webkitallowfullscreen mozallowfullscreen allowfullscreen".split(" "), function (e) {
+                r[e] = {}
+            }), d.parser.addNodeFilter("iframe,video,audio,object,embed,script", oe(d)), d.serializer.addAttributeFilter("data-mce-object", function (e, t) {
+                for (var r, n, i, a, o, c, u, s, l = e.length; l--;) if ((r = e[l]).parent) {
+                    for (u = r.attr(t), n = new te(u, 1), "audio" !== u && "script" !== u && ((s = r.attr("class")) && -1 !== s.indexOf("mce-preview-object") ? n.attr({
+                        width: r.firstChild.attr("width"),
+                        height: r.firstChild.attr("height")
+                    }) : n.attr({
+                        width: r.attr("width"),
+                        height: r.attr("height")
+                    })), n.attr({style: r.attr("style")}), i = (a = r.attributes).length; i--;) {
+                        var m = a[i].name;
+                        0 === m.indexOf("data-mce-p-") && n.attr(m.substr(11), a[i].value)
+                    }
+                    "script" === u && n.attr("type", "text/javascript"), (o = r.attr("data-mce-html")) && ((c = new te("#text", 3)).raw = !0, c.value = ne(d, unescape(o)), n.append(c)), r.replace(n)
+                }
+            })
+        }), d.on("SetContent", function () {
+            d.$("span.mce-preview-object").each(function (e, t) {
+                var r = d.$(t);
+                //TODO 0 === r.find("span.mce-shim").length && r.append('<span class="mce-shim"></span>')
+            })
+        }), (r = e).on("click keyup touchend", function () {
+            var e = r.selection.getNode();
+            e && r.dom.hasClass(e, "mce-preview-object") && r.dom.getAttrib(e, "data-mce-selected") && e.setAttribute("data-mce-selected", "2")
+        }), r.on("ObjectSelected", function (e) {
+            var t = e.target.getAttribute("data-mce-object");
+            "audio" !== t && "script" !== t || e.preventDefault()
+        }), r.on("ObjectResized", function (e) {
+            var t, r = e.target;
+            r.getAttribute("data-mce-object") && (t = r.getAttribute("data-mce-html")) && (t = unescape(t), r.setAttribute("data-mce-html", escape(E(t, {
+                width: String(e.width),
+                height: String(e.height)
+            }))))
+        }), n = e, {
+            showDialog: function () {
+                ee(n)
+            }
+        }
+    })
+}();

+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/nonbreaking/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(n,e){for(var a="",o=0;o<e;o++)a+=n;return a},r=function(n,e){var a,o=n.getParam("nonbreaking_wrap",!0,"boolean")||n.plugins.visualchars?'<span class="'+((a=n).plugins.visualchars&&a.plugins.visualchars.isEnabled()?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap")+'" contenteditable="false">'+i("&nbsp;",e)+"</span>":i("&nbsp;",e);n.undoManager.transact(function(){return n.insertContent(o)})},c=tinymce.util.Tools.resolve("tinymce.util.VK");n.add("nonbreaking",function(n){var e,a,o,i,t;(e=n).addCommand("mceNonBreaking",function(){r(e,1)}),(a=n).ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:function(){return a.execCommand("mceNonBreaking")}}),a.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:function(){return a.execCommand("mceNonBreaking")}}),0<(t="boolean"==typeof(i=(o=n).getParam("nonbreaking_force_tab",0))?!0===i?3:0:i)&&o.on("keydown",function(n){if(n.keyCode===c.TAB&&!n.isDefaultPrevented()){if(n.shiftKey)return;n.preventDefault(),n.stopImmediatePropagation(),r(o,t)}})})}();

+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/noneditable/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=tinymce.util.Tools.resolve("tinymce.util.Tools"),u=function(t){return t.getParam("noneditable_noneditable_class","mceNonEditable")},f=function(e){return function(t){return-1!==(" "+t.attr("class")+" ").indexOf(e)}},e=function(e){var t,r="contenteditable",n=" "+l.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",a=" "+l.trim(u(e))+" ",i=f(n),o=f(a),c=(t=e.getParam("noneditable_regexp",[]))&&t.constructor===RegExp?[t]:t;e.on("PreInit",function(){0<c.length&&e.on("BeforeSetContent",function(t){!function(t,e,n){var r=e.length,a=n.content;if("raw"!==n.format){for(;r--;)a=a.replace(e[r],function(i,o,c){return function(t){var e=arguments,n=e[e.length-2],r=0<n?o.charAt(n-1):"";if('"'===r)return t;if(">"===r){var a=o.lastIndexOf("<",n);if(-1!==a)if(-1!==o.substring(a,n).indexOf('contenteditable="false"'))return t}return'<span class="'+c+'" data-mce-content="'+i.dom.encode(e[0])+'">'+i.dom.encode("string"==typeof e[1]?e[1]:e[0])+"</span>"}}(t,a,u(t)));n.content=a}}(e,c,t)}),e.parser.addAttributeFilter("class",function(t){for(var e,n=t.length;n--;)e=t[n],i(e)?e.attr(r,"true"):o(e)&&e.attr(r,"false")}),e.serializer.addAttributeFilter(r,function(t){for(var e,n=t.length;n--;)e=t[n],(i(e)||o(e))&&(0<c.length&&e.attr("data-mce-content")?(e.name="#text",e.type=3,e.raw=!0,e.value=e.attr("data-mce-content")):e.attr(r,null))})})};t.add("noneditable",function(t){e(t)})}();

+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/pagebreak/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env"),i=function(e){return e.getParam("pagebreak_split_block",!1)},g=function(){return"mce-pagebreak"},m=function(){return'<img src="'+a.transparentSrc+'" class="'+g()+'" data-mce-resize="false" data-mce-placeholder />'};e.add("pagebreak",function(e){var a,n,o,c,t,r;(a=e).addCommand("mcePageBreak",function(){i(a)?a.insertContent("<p>"+m()+"</p>"):a.insertContent(m())}),(n=e).ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:function(){return n.execCommand("mcePageBreak")}}),n.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:function(){return n.execCommand("mcePageBreak")}}),c=(o=e).getParam("pagebreak_separator","\x3c!-- pagebreak --\x3e"),t=new RegExp(c.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),o.on("BeforeSetContent",function(e){e.content=e.content.replace(t,m())}),o.on("PreInit",function(){o.serializer.addNodeFilter("img",function(e){for(var a,n,t=e.length;t--;)if((n=(a=e[t]).attr("class"))&&-1!==n.indexOf("mce-pagebreak")){var r=a.parent;if(o.schema.getBlockElements()[r.name]&&i(o)){r.type=3,r.value=c,r.raw=!0,a.remove();continue}a.type=3,a.value=c,a.raw=!0}})}),(r=e).on("ResolveName",function(e){"IMG"===e.target.nodeName&&r.dom.hasClass(e.target,g())&&(e.name="pagebreak")})})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/paste/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/preview/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),f=tinymce.util.Tools.resolve("tinymce.Env"),w=tinymce.util.Tools.resolve("tinymce.util.Tools"),i=function(e){var t=function(t){var n="",i=t.dom.encode,e=t.getParam("content_style","","string");n+='<base href="'+i(t.documentBaseURI.getURI())+'">',e&&(n+='<style type="text/css">'+e+"</style>");var o=t.getParam("content_css_cors",!1,"boolean")?' crossorigin="anonymous"':"";w.each(t.contentCSS,function(e){n+='<link type="text/css" rel="stylesheet" href="'+i(t.documentBaseURI.toAbsolute(e))+'"'+o+">"});var r,a,c,s,d,m,l,y=-1===(s=(r=t).getParam("body_id","tinymce","string")).indexOf("=")?s:(c=(a=r).getParam("body_id","","hash"))[a.id]||c,u=-1===(l=(d=t).getParam("body_class","","string")).indexOf("=")?l:(m=d).getParam("body_class","","hash")[m.id]||"",v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(f.mac?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",g=t.getBody().dir,p=g?' dir="'+i(g)+'"':"";return"<!DOCTYPE html><html><head>"+n+'</head><body id="'+i(y)+'" class="mce-content-body '+i(u)+'"'+p+">"+t.getContent()+v+"</body></html>"}(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:t}}).focus("close")};e.add("preview",function(e){var t,n;(t=e).addCommand("mcePreview",function(){i(t)}),(n=e).ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:function(){return n.execCommand("mcePreview")}}),n.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:function(){return n.execCommand("mcePreview")}})})}();

+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/print/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),e=tinymce.util.Tools.resolve("tinymce.Env");n.add("print",function(n){var t,i;(t=n).addCommand("mcePrint",function(){e.browser.isIE()?t.getDoc().execCommand("print",!1,null):t.getWin().print()}),(i=n).ui.registry.addButton("print",{icon:"print",tooltip:"Print",onAction:function(){return i.execCommand("mcePrint")}}),i.ui.registry.addMenuItem("print",{text:"Print...",icon:"print",onAction:function(){return i.execCommand("mcePrint")}}),n.addShortcut("Meta+P","","mcePrint")})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/quickbars/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/save/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),o=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),a=tinymce.util.Tools.resolve("tinymce.util.Tools"),i=function(e){return e.getParam("save_enablewhendirty",!0)},c=function(e,n){e.notificationManager.open({text:n,type:"error"})},t=function(t){t.addCommand("mceSave",function(){!function(e){var n=o.DOM.getParent(e.id,"form");if(!i(e)||e.isDirty()){if(e.save(),e.getParam("save_onsavecallback"))return e.execCallback("save_onsavecallback",e),e.nodeChanged();n?(e.setDirty(!1),n.onsubmit&&!n.onsubmit()||("function"==typeof n.submit?n.submit():c(e,"Error: Form submit field collision.")),e.nodeChanged()):c(e,"Error: No form element found.")}}(t)}),t.addCommand("mceCancel",function(){var e,n;e=t,n=a.trim(e.startContent),e.getParam("save_oncancelcallback")?e.execCallback("save_oncancelcallback",e):e.resetContent(n)})},r=function(t){return function(e){var n=function(){e.setDisabled(i(t)&&!t.isDirty())};return t.on("NodeChange dirty",n),function(){return t.off("NodeChange dirty",n)}}};e.add("save",function(e){var n;(n=e).ui.registry.addButton("save",{icon:"save",tooltip:"Save",disabled:!0,onAction:function(){return n.execCommand("mceSave")},onSetup:r(n)}),n.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",disabled:!0,onAction:function(){return n.execCommand("mceCancel")},onSetup:r(n)}),n.addShortcut("Meta+S","","mceSave"),t(e)})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/searchreplace/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/spellchecker/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/tabfocus/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),c=tinymce.util.Tools.resolve("tinymce.EditorManager"),a=tinymce.util.Tools.resolve("tinymce.Env"),y=tinymce.util.Tools.resolve("tinymce.util.Delay"),d=tinymce.util.Tools.resolve("tinymce.util.Tools"),f=tinymce.util.Tools.resolve("tinymce.util.VK"),m=t.DOM,n=function(e){e.keyCode!==f.TAB||e.ctrlKey||e.altKey||e.metaKey||e.preventDefault()},i=function(s){function e(i){var o,l,e,t,n,u;function r(e){var t=m.select(":input:enabled,*[tabindex]:not(iframe)");function n(e){return/INPUT|TEXTAREA|BUTTON/.test(e.tagName)&&c.get(i.id)&&-1!==e.tabIndex&&function t(e){return"BODY"===e.nodeName||"hidden"!==e.type&&"none"!==e.style.display&&"hidden"!==e.style.visibility&&t(e.parentNode)}(e)}if(d.each(t,function(e,t){if(e.id===s.id)return o=t,!1}),0<e){for(l=o+1;l<t.length;l++)if(n(t[l]))return t[l]}else for(l=o-1;0<=l;l--)if(n(t[l]))return t[l];return null}i.keyCode!==f.TAB||i.ctrlKey||i.altKey||i.metaKey||i.isDefaultPrevented()||(1===(e=d.explode((t=s).getParam("tab_focus",t.getParam("tabfocus_elements",":prev,:next")))).length&&(e[1]=e[0],e[0]=":prev"),(n=i.shiftKey?":prev"===e[0]?r(-1):m.get(e[0]):":next"===e[1]?r(1):m.get(e[1]))&&(u=c.get(n.id||n.name),n.id&&u?u.focus():y.setTimeout(function(){a.webkit||window.focus(),n.focus()},10),i.preventDefault()))}s.on("init",function(){s.inline&&m.setAttrib(s.getBody(),"tabIndex",null),s.on("keyup",n),a.gecko?s.on("keypress keydown",e):s.on("keydown",e)})};e.add("tabfocus",function(e){i(e)})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/table/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/template/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/textcolor/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("textcolor",function(){console.warn("Text color plugin is now built in to the core editor, please remove it from your editor configuration")})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/textpattern/plugin.min.js


File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/toc/plugin.min.js


+ 177 - 0
public/assets/v1/common/lib/tinymce/plugins/toolbarsticky/plugin.js

@@ -0,0 +1,177 @@
+(function () {
+  'use strict';
+
+  let global = tinymce.util.Tools.resolve('tinymce.PluginManager');
+  let Global = typeof window !== 'undefined' ? window : Function('return this;')();
+
+  let offset = {};
+  let runtime = {};
+
+  let toolbar_sticky_type = !0;
+  let cfyun_toolbar_sticky = !1;
+  let toolbar_sticky_elem = null;
+  let toolbar_sticky_elem_height = 0;
+  let toolbar_sticky_wrap = null;
+
+  class ToolbarSticky {
+    constructor(editor) {
+
+      cfyun_toolbar_sticky = editor.getParam('cfyun_toolbar_sticky', !1, 'bool');
+
+      if (!cfyun_toolbar_sticky) {
+        return;
+      }
+
+      toolbar_sticky_type = editor.getParam('toolbar_sticky_type', !0, 'bool');
+      toolbar_sticky_elem = editor.getParam('toolbar_sticky_elem', '', 'string');
+      toolbar_sticky_wrap = editor.getParam('toolbar_sticky_wrap', '', 'string');
+      toolbar_sticky_elem_height = editor.getParam('toolbar_sticky_elem_height', 0, 'number');
+
+      this.editor = editor;
+      runtime.wrap = window;
+      runtime.editor = editor.$(editor.container);
+      runtime.header = runtime.editor.find('.tox-editor-header');
+      runtime.container = runtime.editor.find('.tox-editor-container');
+      runtime.elemHeight = toolbar_sticky_elem_height;
+
+      if(toolbar_sticky_wrap && typeof toolbar_sticky_wrap === 'string' && toolbar_sticky_wrap != 'body') {
+        runtime.wrap = document.querySelector(toolbar_sticky_wrap) || window;
+      }
+
+      let _this = this;
+
+      if(toolbar_sticky_type) {
+        editor.on('focus', () => {
+          _this.bind();
+        });
+
+        editor.on('blur', () => {
+          _this.restore();
+          _this.unBind();
+        });
+      } else {
+        this.bind();
+      }
+
+      return this;
+    }
+    sticky() {
+      // 防止全屏冲突
+      if(runtime.editor.hasClass('tox-fullscreen')) {
+        this.restore();
+        return !1;
+      }
+      this.position();
+      if(offset.isSticky) {
+        runtime.container.css('padding-top', runtime.header[0].clientHeight);
+        runtime.editor.removeClass('tox-tinymce--toolbar-sticky-off').addClass('tox-tinymce--toolbar-sticky-on');
+        runtime.header.css({
+          position: 'fixed',
+          width: offset.width,
+          left: offset.left,
+          top: runtime.elemHeight || 0,
+          borderTop: '1px solid #ccc'
+        });
+        return !1;
+      }
+
+      this.restore();
+    }
+    position() {
+      let elemOffsetHeight = runtime.elemHeight;
+      if (toolbar_sticky_elem) {
+        var elem = document.querySelector(toolbar_sticky_elem);
+        if(!elem) {
+          // 防止配置不正确报错
+          this.editor.notificationManager.open({
+            text: 'ToolbarSticky未获取到:预留位置DOM节点,请查看配置toolbar_sticky_elem。',
+            type: 'info',
+          });
+          return !1;
+        }
+        elemOffsetHeight = elem.offsetHeight;
+        runtime.elemHeight = elem.clientHeight;
+      }
+      offset.width = this.editor.container.clientWidth;
+      offset.left = runtime.editor.offset().left + 1;
+      offset.isSticky = this.scrollTop() >= this.editor.$(runtime.container).offset().top - elemOffsetHeight;
+    }
+    bind() {
+      runtime.wrap.addEventListener('scroll', this.throttle(this.sticky.bind(this), 60), !1);
+      runtime.wrap.addEventListener('resize', this.throttle(this.sticky.bind(this), 60), !1);
+      this.sticky()
+    }
+    unBind() {
+      runtime.wrap.removeEventListener('scroll', this.throttle(this.sticky.bind(this), 60));
+      runtime.wrap.removeEventListener('resize', this.throttle(this.sticky.bind(this), 60));
+    }
+    restore() {
+      runtime.header.attr('style', '');
+      runtime.container.css('padding-top', 0);
+      runtime.editor.removeClass('tox-tinymce--toolbar-sticky-on').addClass('tox-tinymce--toolbar-sticky-off')
+    }
+    destroy() {
+      offset = runtime = {};
+      this.unBind();
+      this.restore()
+    }
+    scrollTop() {
+      return document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset
+    }
+    now() {
+      return Date.now() || new Date().getTime()
+    }
+    /**
+     * 函数节流
+     * @param {func} fn
+     * @param {number} delay
+     */
+    throttle(fn, delay) {
+      let _this = this, context, args, result;
+      let timeout = null;
+      let previous = 0;
+      const later = () => {
+        previous = 0;
+        timeout = null;
+        result = fn.apply(context, args);
+        if (!timeout) {
+          context = args = null;
+        }
+      };
+      return () => {
+        let now = _this.now();
+        if (!previous) {
+          previous = now;
+        }
+        let remaining = delay - (now - previous);
+        context = this;
+        args = arguments;
+        if (remaining <= 0 || remaining > delay) {
+          if (timeout) {
+            clearTimeout(timeout);
+            timeout = null;
+          }
+          previous = now;
+          result = fn.apply(context, args);
+          if (!timeout) {
+            context = args = null;
+          }
+        } else if (!timeout) {
+          timeout = setTimeout(later, remaining);
+        }
+        return result;
+      };
+    }
+  }
+
+  function Plugin () {
+    global.add('toolbarsticky', function (editor) {
+      editor.on('init', function (e) {
+        new ToolbarSticky(editor)
+      });
+    });
+  }
+
+  Plugin();
+
+}());

File diff suppressed because it is too large
+ 0 - 0
public/assets/v1/common/lib/tinymce/plugins/toolbarsticky/plugin.min.js


+ 9 - 0
public/assets/v1/common/lib/tinymce/plugins/visualblocks/plugin.min.js

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) Tiny Technologies, Inc. All rights reserved.
+ * Licensed under the LGPL or a commercial license.
+ * For LGPL see License.txt in the project root for license information.
+ * For commercial licenses see https://www.tiny.cloud/
+ *
+ * Version: 5.6.0 (2020-11-18)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),r=function(t,o,e){var n,i;t.dom.toggleClass(t.getBody(),"mce-visualblocks"),e.set(!e.get()),n=t,i=e.get(),n.fire("VisualBlocks",{state:i})},f=function(e,n){return function(o){o.setActive(n.get());var t=function(t){return o.setActive(t.state)};return e.on("VisualBlocks",t),function(){return e.off("VisualBlocks",t)}}};t.add("visualblocks",function(t,o){var e,n,i,s,c,u,l,a=(e=!1,{get:function(){return e},set:function(t){e=t}});i=a,(n=t).addCommand("mceVisualBlocks",function(){r(n,0,i)}),c=a,(s=t).ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:function(){return s.execCommand("mceVisualBlocks")},onSetup:f(s,c)}),s.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:function(){return s.execCommand("mceVisualBlocks")},onSetup:f(s,c)}),l=a,(u=t).on("PreviewFormats AfterPreviewFormats",function(t){l.get()&&u.dom.toggleClass(u.getBody(),"mce-visualblocks","afterpreviewformats"===t.type)}),u.on("init",function(){u.getParam("visualblocks_default_state",!1,"boolean")&&r(u,0,l)})})}();

File diff suppressed because it is too large
+ 8 - 0
public/assets/v1/common/lib/tinymce/plugins/visualchars/plugin.min.js


Some files were not shown because too many files changed in this diff