Repository: nylas/nylas-mail Branch: master Commit: e16cb1982e94 Files: 1760 Total size: 8.0 MB Directory structure: gitextract_fft17z4s/ ├── .babelrc ├── .coffeelint.json ├── .dockerignore ├── .ebextensions/ │ └── enable_docker_cli_on_ssh.config ├── .ebignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── Dockerfile ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── appveyor.yml ├── lerna.json ├── package.json ├── packages/ │ ├── README.md │ ├── client-app/ │ │ ├── .babelrc │ │ ├── .travis.yml │ │ ├── .watchmanconfig │ │ ├── CHANGELOG.md │ │ ├── CONFIGURATION.md │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── apm/ │ │ │ ├── README.md │ │ │ └── package.json │ │ ├── build/ │ │ │ ├── Gruntfile.js │ │ │ ├── README.md │ │ │ ├── config/ │ │ │ │ └── coffeelint.json │ │ │ ├── docs_templates/ │ │ │ │ ├── _function.html │ │ │ │ ├── _property.html │ │ │ │ ├── class.md │ │ │ │ └── sidebar.md │ │ │ ├── resources/ │ │ │ │ ├── asar-ordering-hint.txt │ │ │ │ ├── linux/ │ │ │ │ │ ├── debian/ │ │ │ │ │ │ ├── control.in │ │ │ │ │ │ ├── lintian-overrides │ │ │ │ │ │ ├── postinst │ │ │ │ │ │ └── postrm │ │ │ │ │ ├── nylas-mail.desktop.in │ │ │ │ │ └── redhat/ │ │ │ │ │ └── nylas.spec.in │ │ │ │ ├── mac/ │ │ │ │ │ ├── Nylas Calendar.app/ │ │ │ │ │ │ └── Contents/ │ │ │ │ │ │ ├── Info.plist │ │ │ │ │ │ ├── MacOS/ │ │ │ │ │ │ │ └── Nylas Calendar │ │ │ │ │ │ ├── PkgInfo │ │ │ │ │ │ ├── Resources/ │ │ │ │ │ │ │ ├── AppIcon.icns │ │ │ │ │ │ │ └── Base.lproj/ │ │ │ │ │ │ │ └── MainMenu.nib │ │ │ │ │ │ └── _CodeSignature/ │ │ │ │ │ │ └── CodeResources │ │ │ │ │ ├── file.icns │ │ │ │ │ ├── nylas-Info.plist │ │ │ │ │ └── nylas.icns │ │ │ │ ├── ssh/ │ │ │ │ │ ├── nylas-n1-ci-ssh-secure-file.enc │ │ │ │ │ └── nylas-n1-ci-ssh.openssl.enc │ │ │ │ └── win/ │ │ │ │ ├── elevate.cmd │ │ │ │ ├── elevate.vbs │ │ │ │ ├── nylas-mailto-default.reg │ │ │ │ └── nylas-mailto-registration.reg │ │ │ └── tasks/ │ │ │ ├── coffeelint-task.js │ │ │ ├── create-mac-dmg.js │ │ │ ├── create-mac-zip.js │ │ │ ├── csslint-task.js │ │ │ ├── docs-build-task.js │ │ │ ├── docs-render-task.js │ │ │ ├── docs-task.js │ │ │ ├── eslint-task.js │ │ │ ├── installer-linux-task.js │ │ │ ├── lesslint-task.js │ │ │ ├── nylaslint-task.js │ │ │ ├── package-task.js │ │ │ └── task-helpers.js │ │ ├── docs/ │ │ │ ├── ContinuousIntegration.md │ │ │ └── README.md │ │ ├── dot-nylas/ │ │ │ ├── README.md │ │ │ ├── config.json │ │ │ ├── keymap.json │ │ │ └── packages/ │ │ │ └── README.md │ │ ├── internal_packages/ │ │ │ ├── account-sidebar/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── account-commands.coffee │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── account-sidebar.cjsx │ │ │ │ │ │ └── account-switcher.cjsx │ │ │ │ │ ├── main.coffee │ │ │ │ │ ├── sidebar-actions.coffee │ │ │ │ │ ├── sidebar-item.coffee │ │ │ │ │ ├── sidebar-section.coffee │ │ │ │ │ └── sidebar-store.coffee │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── sidebar-item-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ └── account-sidebar.less │ │ │ ├── activity-list/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── activity-data-source.es6 │ │ │ │ │ ├── activity-list-actions.es6 │ │ │ │ │ ├── activity-list-button.jsx │ │ │ │ │ ├── activity-list-empty-state.jsx │ │ │ │ │ ├── activity-list-item-container.jsx │ │ │ │ │ ├── activity-list-store.jsx │ │ │ │ │ ├── activity-list.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── plugin-helpers.es6 │ │ │ │ │ └── test-data-source.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── activity-list-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ └── activity-list.less │ │ │ ├── attachments/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── message-attachments.jsx │ │ │ │ └── package.json │ │ │ ├── category-mapper/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── category-selection.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── preferences-category-mapper.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── category-mapper.less │ │ │ ├── category-picker/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── category-picker-popover.jsx │ │ │ │ │ ├── category-picker.cjsx │ │ │ │ │ └── main.cjsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── category-picker-spec.cjsx │ │ │ │ └── stylesheets/ │ │ │ │ └── category-picker.less │ │ │ ├── composer/ │ │ │ │ ├── README.md │ │ │ │ ├── keymaps/ │ │ │ │ │ └── composer.json │ │ │ │ ├── lib/ │ │ │ │ │ ├── account-contact-field.jsx │ │ │ │ │ ├── action-bar-plugins.jsx │ │ │ │ │ ├── collapsed-participants.jsx │ │ │ │ │ ├── compose-button.jsx │ │ │ │ │ ├── composer-editor.jsx │ │ │ │ │ ├── composer-header-actions.jsx │ │ │ │ │ ├── composer-header.jsx │ │ │ │ │ ├── composer-view.jsx │ │ │ │ │ ├── fields.es6 │ │ │ │ │ ├── image-upload-composer-extension.es6 │ │ │ │ │ ├── inline-image-upload-container.jsx │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── send-action-button.jsx │ │ │ │ │ └── subject-text-field.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── collapsed-participants-spec.cjsx │ │ │ │ │ ├── composer-header-actions-spec.cjsx │ │ │ │ │ ├── composer-header-spec.jsx │ │ │ │ │ ├── composer-view-spec.cjsx │ │ │ │ │ ├── quoted-text-spec.cjsx │ │ │ │ │ └── send-action-button-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ └── composer.less │ │ │ ├── composer-emoji/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── categorized-emoji.es6 │ │ │ │ │ ├── emoji-actions.es6 │ │ │ │ │ ├── emoji-button-popover.jsx │ │ │ │ │ ├── emoji-button.jsx │ │ │ │ │ ├── emoji-composer-extension.jsx │ │ │ │ │ ├── emoji-data.json │ │ │ │ │ ├── emoji-message-extension.jsx │ │ │ │ │ ├── emoji-picker.jsx │ │ │ │ │ ├── emoji-store.jsx │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── emoji-button-popover-spec.jsx │ │ │ │ │ └── emoji-composer-extension-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ └── composer-emoji.less │ │ │ ├── composer-mail-merge/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── listens-to-mail-merge-session.jsx │ │ │ │ │ ├── mail-merge-body-token.jsx │ │ │ │ │ ├── mail-merge-button.jsx │ │ │ │ │ ├── mail-merge-composer-extension.es6 │ │ │ │ │ ├── mail-merge-constants.es6 │ │ │ │ │ ├── mail-merge-container.jsx │ │ │ │ │ ├── mail-merge-draft-editing-session.es6 │ │ │ │ │ ├── mail-merge-header-input.jsx │ │ │ │ │ ├── mail-merge-participants-text-field.jsx │ │ │ │ │ ├── mail-merge-send-button.jsx │ │ │ │ │ ├── mail-merge-subject-text-field.jsx │ │ │ │ │ ├── mail-merge-table.jsx │ │ │ │ │ ├── mail-merge-token-dnd-handlers.es6 │ │ │ │ │ ├── mail-merge-token.jsx │ │ │ │ │ ├── mail-merge-utils.es6 │ │ │ │ │ ├── mail-merge-workspace.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── selection-state-reducers.es6 │ │ │ │ │ ├── send-many-drafts-task.es6 │ │ │ │ │ ├── table-state-reducers.es6 │ │ │ │ │ ├── token-data-source.es6 │ │ │ │ │ ├── token-state-reducers.es6 │ │ │ │ │ └── workspace-state-reducers.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── fixtures.es6 │ │ │ │ │ ├── mail-merge-draft-editing-session-spec.es6 │ │ │ │ │ ├── mail-merge-utils-spec.es6 │ │ │ │ │ ├── selection-state-reducers-spec.es6 │ │ │ │ │ ├── send-many-drafts-task-spec.es6 │ │ │ │ │ ├── table-state-reducers-spec.es6 │ │ │ │ │ ├── token-state-reducers-spec.es6 │ │ │ │ │ └── workspace-state-reducers-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ └── mail-merge.less │ │ │ ├── composer-markdown/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.cjsx │ │ │ │ │ ├── markdown-composer-extension.coffee │ │ │ │ │ ├── markdown-editor.cjsx │ │ │ │ │ └── utils.coffee │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── index.less │ │ │ ├── composer-scheduler/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── calendar/ │ │ │ │ │ │ ├── proposed-time-calendar-data-source.es6 │ │ │ │ │ │ ├── proposed-time-event.jsx │ │ │ │ │ │ └── proposed-time-picker.jsx │ │ │ │ │ ├── composer/ │ │ │ │ │ │ ├── email-b64-images.es6 │ │ │ │ │ │ ├── email-images.json │ │ │ │ │ │ ├── event-datetime-input.jsx │ │ │ │ │ │ ├── event-prep-helper.es6 │ │ │ │ │ │ ├── new-event-card-container.jsx │ │ │ │ │ │ ├── new-event-card.jsx │ │ │ │ │ │ ├── new-event-helper.es6 │ │ │ │ │ │ ├── new-event-preview.jsx │ │ │ │ │ │ ├── proposed-time-list.jsx │ │ │ │ │ │ ├── remove-event-helper.es6 │ │ │ │ │ │ ├── scheduler-composer-button.jsx │ │ │ │ │ │ └── scheduler-composer-extension.es6 │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── proposal.es6 │ │ │ │ │ ├── proposed-time-calendar-store.es6 │ │ │ │ │ ├── scheduler-actions.es6 │ │ │ │ │ └── scheduler-constants.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── composer-scheduler-spec-helper.es6 │ │ │ │ │ ├── new-event-card-spec.jsx │ │ │ │ │ ├── proposed-time-picker-spec.jsx │ │ │ │ │ ├── scheduler-composer-button-spec.jsx │ │ │ │ │ ├── scheduler-composer-extension-spec.es6 │ │ │ │ │ └── test-proposal-data-source.es6 │ │ │ │ └── stylesheets/ │ │ │ │ └── scheduler.less │ │ │ ├── composer-signature/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── preferences-signatures.jsx │ │ │ │ │ ├── signature-composer-dropdown.jsx │ │ │ │ │ ├── signature-composer-extension.es6 │ │ │ │ │ └── signature-utils.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── preferences-signatures-spec.jsx │ │ │ │ │ ├── signature-composer-dropdown-spec.jsx │ │ │ │ │ ├── signature-composer-extension-spec.es6 │ │ │ │ │ └── signature-store-spec.jsx │ │ │ │ └── styles/ │ │ │ │ └── composer-signature.less │ │ │ ├── composer-spellcheck/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── spellcheck-composer-extension.es6 │ │ │ │ ├── package.json │ │ │ │ └── spec/ │ │ │ │ ├── fixtures/ │ │ │ │ │ ├── california-spelling-lookup.json │ │ │ │ │ ├── california-with-misspellings-after.html │ │ │ │ │ └── california-with-misspellings-before.html │ │ │ │ └── spellcheck-composer-extension-spec.es6 │ │ │ ├── composer-templates/ │ │ │ │ ├── README.md │ │ │ │ ├── assets/ │ │ │ │ │ └── Welcome to Quick Replies.html │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── preferences-templates.jsx │ │ │ │ │ ├── template-composer-extension.es6 │ │ │ │ │ ├── template-editor.es6 │ │ │ │ │ ├── template-picker.jsx │ │ │ │ │ ├── template-status-bar.jsx │ │ │ │ │ └── template-store.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── template-store-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ └── message-templates.less │ │ │ ├── composer-translate/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ └── main.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── translate.less │ │ │ ├── contact-rankings/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── contact-rankings-cache.es6 │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── refreshing-json-cache.coffee │ │ │ │ └── package.json │ │ │ ├── draft-list/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── draft-list-columns.cjsx │ │ │ │ │ ├── draft-list-send-status.jsx │ │ │ │ │ ├── draft-list-store.coffee │ │ │ │ │ ├── draft-list-toolbar.jsx │ │ │ │ │ ├── draft-list.cjsx │ │ │ │ │ ├── draft-toolbar-buttons.cjsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── sending-cancel-button.cjsx │ │ │ │ │ └── sending-progress-bar.cjsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── draft-list.less │ │ │ ├── events/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── event-header.cjsx │ │ │ │ │ └── main.cjsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── events.less │ │ │ ├── github-contact-card/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── github-contact-card-section.jsx │ │ │ │ │ ├── github-user-store.es6 │ │ │ │ │ └── main.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── sidebar-github-profile.less │ │ │ ├── keybase/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── decrypt-button.cjsx │ │ │ │ │ ├── decryption-preprocess.coffee │ │ │ │ │ ├── email-popover.cjsx │ │ │ │ │ ├── encrypt-button.cjsx │ │ │ │ │ ├── identity.coffee │ │ │ │ │ ├── key-adder.cjsx │ │ │ │ │ ├── key-manager.cjsx │ │ │ │ │ ├── keybase-search.cjsx │ │ │ │ │ ├── keybase-user.cjsx │ │ │ │ │ ├── keybase.coffee │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── modal-key-recommender.cjsx │ │ │ │ │ ├── passphrase-popover.cjsx │ │ │ │ │ ├── pgp-key-store.cjsx │ │ │ │ │ ├── preferences-keybase.cjsx │ │ │ │ │ ├── private-key-popover.cjsx │ │ │ │ │ └── recipient-key-chip.cjsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── decrypt-buttons-spec.cjsx │ │ │ │ │ ├── encrypt-button-spec.cjsx │ │ │ │ │ ├── keybase-profile-spec.cjsx │ │ │ │ │ ├── keybase-search-spec.cjsx │ │ │ │ │ ├── keybase-spec.coffee │ │ │ │ │ ├── main-spec.coffee │ │ │ │ │ ├── pgp-key-store-spec.cjsx │ │ │ │ │ └── recipient-key-chip-spec.cjsx │ │ │ │ └── stylesheets/ │ │ │ │ └── main.less │ │ │ ├── link-tracking/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── link-tracking-button.jsx │ │ │ │ │ ├── link-tracking-composer-extension.es6 │ │ │ │ │ ├── link-tracking-constants.es6 │ │ │ │ │ ├── link-tracking-message-extension.jsx │ │ │ │ │ ├── link-tracking-message-popover.jsx │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── link-tracking-composer-extension-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ └── main.less │ │ │ ├── main-calendar/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── calendar-wrapper.jsx │ │ │ │ │ ├── event-description-frame.jsx │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── quick-event-button.jsx │ │ │ │ │ └── quick-event-popover.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── main-calendar.less │ │ │ ├── message-autoload-images/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── autoload-images-actions.es6 │ │ │ │ │ ├── autoload-images-extension.es6 │ │ │ │ │ ├── autoload-images-header.jsx │ │ │ │ │ ├── autoload-images-store.es6 │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── autoload-images-extension-spec.es6 │ │ │ │ │ └── fixtures/ │ │ │ │ │ ├── linkedin-in.html │ │ │ │ │ ├── linkedin-out.html │ │ │ │ │ ├── marketing-email-in.html │ │ │ │ │ ├── marketing-email-out.html │ │ │ │ │ ├── no-image-extensions-in.html │ │ │ │ │ ├── no-image-extensions-out.html │ │ │ │ │ ├── table-body-in.html │ │ │ │ │ └── table-body-out.html │ │ │ │ └── stylesheets/ │ │ │ │ └── message-autoload-images.less │ │ │ ├── message-list/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── autolinker.es6 │ │ │ │ │ ├── autoscale-images.es6 │ │ │ │ │ ├── email-frame-styles-store.coffee │ │ │ │ │ ├── email-frame.jsx │ │ │ │ │ ├── find-in-thread.jsx │ │ │ │ │ ├── inline-image-listeners.es6 │ │ │ │ │ ├── main.cjsx │ │ │ │ │ ├── message-controls.cjsx │ │ │ │ │ ├── message-item-body.cjsx │ │ │ │ │ ├── message-item-container.cjsx │ │ │ │ │ ├── message-item.cjsx │ │ │ │ │ ├── message-list-hidden-messages-toggle.jsx │ │ │ │ │ ├── message-list.cjsx │ │ │ │ │ ├── message-participants.cjsx │ │ │ │ │ ├── message-timestamp.jsx │ │ │ │ │ ├── sidebar-participant-picker.jsx │ │ │ │ │ ├── sidebar-plugin-container.cjsx │ │ │ │ │ ├── thread-archive-button.cjsx │ │ │ │ │ ├── thread-star-button.cjsx │ │ │ │ │ ├── thread-toggle-unread-button.cjsx │ │ │ │ │ └── thread-trash-button.cjsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── autolinker-fixtures/ │ │ │ │ │ │ ├── both-email-and-url-in.html │ │ │ │ │ │ ├── both-email-and-url-out.html │ │ │ │ │ │ ├── gmail-in.html │ │ │ │ │ │ ├── gmail-out.html │ │ │ │ │ │ ├── linkedin-in.html │ │ │ │ │ │ ├── linkedin-out.html │ │ │ │ │ │ ├── medium-post-in.html │ │ │ │ │ │ ├── medium-post-out.html │ │ │ │ │ │ ├── nylas-url-in.html │ │ │ │ │ │ ├── nylas-url-out.html │ │ │ │ │ │ ├── plaintext-in.html │ │ │ │ │ │ ├── plaintext-out.html │ │ │ │ │ │ ├── readme-in.html │ │ │ │ │ │ ├── readme-out.html │ │ │ │ │ │ ├── strangeemails-in.html │ │ │ │ │ │ ├── strangeemails-out.html │ │ │ │ │ │ ├── strangephones-in.html │ │ │ │ │ │ ├── strangephones-out.html │ │ │ │ │ │ ├── twitter-in.html │ │ │ │ │ │ ├── twitter-out.html │ │ │ │ │ │ ├── url-with-port-in.html │ │ │ │ │ │ └── url-with-port-out.html │ │ │ │ │ ├── autolinker-spec.es6 │ │ │ │ │ ├── message-item-body-spec.cjsx │ │ │ │ │ ├── message-item-container-spec.cjsx │ │ │ │ │ ├── message-item-spec.cjsx │ │ │ │ │ ├── message-list-spec.cjsx │ │ │ │ │ ├── message-participants-spec.cjsx │ │ │ │ │ └── message-timestamp-spec.cjsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── find-in-thread.less │ │ │ │ └── message-list.less │ │ │ ├── message-view-on-github/ │ │ │ │ ├── README.md │ │ │ │ ├── keymaps/ │ │ │ │ │ └── github.json │ │ │ │ ├── lib/ │ │ │ │ │ ├── github-store.es6 │ │ │ │ │ ├── main.jsx │ │ │ │ │ └── view-on-github-button.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── github.less │ │ │ ├── mode-switch/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── mode-toggle.cjsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── mode-switch.less │ │ │ ├── notifications/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── items/ │ │ │ │ │ │ ├── account-error-notif.jsx │ │ │ │ │ │ ├── default-client-notif.jsx │ │ │ │ │ │ ├── dev-mode-notif.jsx │ │ │ │ │ │ ├── disabled-mail-rules-notif.jsx │ │ │ │ │ │ └── offline-notification.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── notif-wrapper.jsx │ │ │ │ │ └── sidebar/ │ │ │ │ │ ├── activity-sidebar.cjsx │ │ │ │ │ ├── initial-sync-activity.jsx │ │ │ │ │ ├── sync-activity.jsx │ │ │ │ │ └── syncback-activity.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── account-error-notif-spec.jsx │ │ │ │ │ ├── default-client-notif-spec.jsx │ │ │ │ │ ├── dev-mode-notif-spec.jsx │ │ │ │ │ ├── disabled-mail-rules-notif-spec.jsx │ │ │ │ │ └── priority-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── notifications.less │ │ │ │ └── styles.less │ │ │ ├── nylas-private-fonts/ │ │ │ │ ├── fonts/ │ │ │ │ │ ├── Nylas-Pro-Blond.otf │ │ │ │ │ ├── Nylas-Pro-Hair.otf │ │ │ │ │ ├── Nylas-Pro-Light.otf │ │ │ │ │ ├── Nylas-Pro-Medium.otf │ │ │ │ │ ├── Nylas-Pro-Normal.otf │ │ │ │ │ ├── Nylas-Pro-SemiBold.otf │ │ │ │ │ └── Nylas-Pro-Thin.otf │ │ │ │ ├── lib/ │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── nylas-fonts.less │ │ │ ├── nylas-private-salesforce/ │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── keymaps/ │ │ │ │ │ └── salesforce.json │ │ │ │ ├── lib/ │ │ │ │ │ ├── composer/ │ │ │ │ │ │ ├── contact-search-results.jsx │ │ │ │ │ │ ├── participant-decorator.jsx │ │ │ │ │ │ └── salesforce-composer-picker.jsx │ │ │ │ │ ├── contact/ │ │ │ │ │ │ └── salesforce-contact-info.jsx │ │ │ │ │ ├── form/ │ │ │ │ │ │ ├── fetch-empty-schema-for-type.es6 │ │ │ │ │ │ ├── form-data-helpers.es6 │ │ │ │ │ │ ├── generated-form-to-salesforce-adapter.es6 │ │ │ │ │ │ ├── pending-salesforce-object.es6 │ │ │ │ │ │ ├── remove-controls.jsx │ │ │ │ │ │ ├── salesforce-object-form.jsx │ │ │ │ │ │ ├── salesforce-object-picker.jsx │ │ │ │ │ │ ├── salesforce-schema-adapter.es6 │ │ │ │ │ │ ├── salesforce-window-launcher.es6 │ │ │ │ │ │ └── smart-fields.es6 │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── metadata-helpers.es6 │ │ │ │ │ ├── models/ │ │ │ │ │ │ ├── salesforce-object.es6 │ │ │ │ │ │ └── salesforce-schema.es6 │ │ │ │ │ ├── related-object-helpers.es6 │ │ │ │ │ ├── salesforce-actions.es6 │ │ │ │ │ ├── salesforce-api-error.es6 │ │ │ │ │ ├── salesforce-api.jsx │ │ │ │ │ ├── salesforce-constants.es6 │ │ │ │ │ ├── salesforce-contact-crawler.es6 │ │ │ │ │ ├── salesforce-data-reset.es6 │ │ │ │ │ ├── salesforce-env.es6 │ │ │ │ │ ├── salesforce-error-reporter.es6 │ │ │ │ │ ├── salesforce-intro-notification.jsx │ │ │ │ │ ├── salesforce-metadata-cleanup-listener.es6 │ │ │ │ │ ├── salesforce-new-mail-listener.es6 │ │ │ │ │ ├── salesforce-oauth.jsx │ │ │ │ │ ├── salesforce-object-helpers.es6 │ │ │ │ │ ├── salesforce-related-object-cache.es6 │ │ │ │ │ ├── salesforce-sync-worker.es6 │ │ │ │ │ ├── search/ │ │ │ │ │ │ ├── salesforce-search-bar-results.jsx │ │ │ │ │ │ └── salesforce-search-indexer.es6 │ │ │ │ │ ├── shared-components/ │ │ │ │ │ │ ├── open-in-salesforce-btn.jsx │ │ │ │ │ │ ├── salesforce-icon.jsx │ │ │ │ │ │ └── salesforce-login-prompt.jsx │ │ │ │ │ ├── tasks/ │ │ │ │ │ │ ├── destroy-message-on-salesforce-task.es6 │ │ │ │ │ │ ├── destroy-salesforce-object-task.es6 │ │ │ │ │ │ ├── ensure-message-on-salesforce-task.es6 │ │ │ │ │ │ ├── manually-relate-salesforce-object-task.es6 │ │ │ │ │ │ ├── remove-manual-relation-to-salesforce-object-task.es6 │ │ │ │ │ │ ├── sync-salesforce-objects-task.es6 │ │ │ │ │ │ ├── sync-thread-activity-to-salesforce-task.es6 │ │ │ │ │ │ ├── syncback-salesforce-object-task.es6 │ │ │ │ │ │ └── upsert-opportunity-contact-role-task.es6 │ │ │ │ │ └── thread/ │ │ │ │ │ ├── related-objects-for-thread.jsx │ │ │ │ │ ├── salesforce-manually-relate-thread-button.jsx │ │ │ │ │ ├── salesforce-manually-relate-thread-popover.jsx │ │ │ │ │ ├── salesforce-sync-label.jsx │ │ │ │ │ ├── salesforce-sync-message-status.jsx │ │ │ │ │ └── sync-thread-toggle.jsx │ │ │ │ ├── menus/ │ │ │ │ │ └── salesforce.json │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ ├── opportunity-layouts-alt.json │ │ │ │ │ │ └── opportunity-layouts.json │ │ │ │ │ ├── form-builder-spec.jsx │ │ │ │ │ ├── generate-test-data.es6 │ │ │ │ │ ├── salesforce-schema-adapter-spec.es6 │ │ │ │ │ └── syncback-salesforce-object-task-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ ├── open-in-salesforce-btn.less │ │ │ │ ├── salesforce-association.less │ │ │ │ ├── salesforce-composer.less │ │ │ │ ├── salesforce-contact.less │ │ │ │ ├── salesforce-icon.less │ │ │ │ ├── salesforce-object-form.less │ │ │ │ ├── salesforce-object-picker.less │ │ │ │ ├── salesforce-picker.less │ │ │ │ ├── salesforce-related-object.less │ │ │ │ ├── salesforce-sync-label.less │ │ │ │ ├── salesforce-sync-message-status.less │ │ │ │ ├── salesforce-welcome-view.less │ │ │ │ ├── search-results.less │ │ │ │ └── sync-thread-toggle.less │ │ │ ├── nylas-private-sounds/ │ │ │ │ ├── NYLAS_UI_Confirm_v1.ogg │ │ │ │ ├── NYLAS_UI_HitSend_v1.ogg │ │ │ │ ├── NYLAS_UI_NewMail_v1.ogg │ │ │ │ ├── NYLAS_UI_Send_v1.ogg │ │ │ │ ├── lib/ │ │ │ │ │ └── main.es6 │ │ │ │ └── package.json │ │ │ ├── onboarding/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── account-types.es6 │ │ │ │ │ ├── decorators/ │ │ │ │ │ │ └── create-page-for-form.jsx │ │ │ │ │ ├── form-error-message.jsx │ │ │ │ │ ├── form-field.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── onboarding-actions.es6 │ │ │ │ │ ├── onboarding-helpers.es6 │ │ │ │ │ ├── onboarding-root.jsx │ │ │ │ │ ├── onboarding-store.es6 │ │ │ │ │ ├── page-account-choose.jsx │ │ │ │ │ ├── page-account-onboarding-success.jsx │ │ │ │ │ ├── page-account-settings-exchange.jsx │ │ │ │ │ ├── page-account-settings-gmail.jsx │ │ │ │ │ ├── page-account-settings-imap.jsx │ │ │ │ │ ├── page-account-settings.jsx │ │ │ │ │ ├── page-initial-preferences.cjsx │ │ │ │ │ ├── page-top-bar.jsx │ │ │ │ │ └── page-welcome.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ ├── onboarding-reset.less │ │ │ │ └── onboarding.less │ │ │ ├── open-tracking/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── open-tracking-button.jsx │ │ │ │ │ ├── open-tracking-composer-extension.es6 │ │ │ │ │ ├── open-tracking-constants.es6 │ │ │ │ │ ├── open-tracking-icon.jsx │ │ │ │ │ ├── open-tracking-message-popover.jsx │ │ │ │ │ └── open-tracking-message-status.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── open-tracking-composer-extension-spec.es6 │ │ │ │ │ ├── open-tracking-icon-spec.jsx │ │ │ │ │ └── open-tracking-message-status-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ └── main.less │ │ │ ├── participant-profile/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── clearbit-data-source.coffee │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── participant-profile-store.es6 │ │ │ │ │ ├── sidebar-participant-profile.jsx │ │ │ │ │ └── sidebar-related-threads.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── participant-profile.less │ │ │ ├── personal-level-indicators/ │ │ │ │ ├── README.md │ │ │ │ ├── docs/ │ │ │ │ │ ├── docco.css │ │ │ │ │ ├── personal-level-icon.html │ │ │ │ │ └── public/ │ │ │ │ │ └── stylesheets/ │ │ │ │ │ └── normalize.css │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── personal-level-icon.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── main.less │ │ │ ├── phishing-detection/ │ │ │ │ ├── README.md │ │ │ │ ├── docs/ │ │ │ │ │ ├── docco.css │ │ │ │ │ ├── main.coffee │ │ │ │ │ ├── main.html │ │ │ │ │ └── public/ │ │ │ │ │ └── stylesheets/ │ │ │ │ │ └── normalize.css │ │ │ │ ├── lib/ │ │ │ │ │ └── main.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── main-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── index.less │ │ │ │ └── phishing.less │ │ │ ├── plugins/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── package-set.jsx │ │ │ │ │ ├── package.jsx │ │ │ │ │ ├── packages-store.jsx │ │ │ │ │ ├── plugins-actions.jsx │ │ │ │ │ ├── plugins-tabs-view.jsx │ │ │ │ │ ├── preferences-plugins.jsx │ │ │ │ │ ├── tab-explore.jsx │ │ │ │ │ ├── tab-installed.jsx │ │ │ │ │ ├── tabs-store.jsx │ │ │ │ │ └── tabs.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── plugins.less │ │ │ ├── preferences/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── preferences-root.jsx │ │ │ │ │ ├── preferences-tabs-bar.jsx │ │ │ │ │ └── tabs/ │ │ │ │ │ ├── config-schema-item.jsx │ │ │ │ │ ├── keymaps/ │ │ │ │ │ │ ├── command-item.jsx │ │ │ │ │ │ ├── displayed-keybindings.js │ │ │ │ │ │ └── mousetrap-keybinding-helpers.js │ │ │ │ │ ├── preferences-account-details.jsx │ │ │ │ │ ├── preferences-account-list.jsx │ │ │ │ │ ├── preferences-accounts.jsx │ │ │ │ │ ├── preferences-appearance.jsx │ │ │ │ │ ├── preferences-general.jsx │ │ │ │ │ ├── preferences-keymaps.jsx │ │ │ │ │ ├── preferences-mail-rules.jsx │ │ │ │ │ ├── sending-section.jsx │ │ │ │ │ └── workspace-section.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── preferences-account-details-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── preferences-accounts.less │ │ │ │ ├── preferences-identity.less │ │ │ │ ├── preferences-mail-rules.less │ │ │ │ └── preferences.less │ │ │ ├── print/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── print-window.es6 │ │ │ │ │ └── printer.es6 │ │ │ │ ├── package.json │ │ │ │ └── static/ │ │ │ │ ├── print-styles.css │ │ │ │ └── print.js │ │ │ ├── remove-tracking-pixels/ │ │ │ │ ├── lib/ │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ └── spec/ │ │ │ │ ├── fixtures/ │ │ │ │ │ ├── a-after.txt │ │ │ │ │ ├── a-before.txt │ │ │ │ │ ├── b-after.txt │ │ │ │ │ └── b-before.txt │ │ │ │ └── tracking-pixels-extension-spec.es6 │ │ │ ├── screenshot-mode/ │ │ │ │ ├── assets/ │ │ │ │ │ ├── BLOKKNeue-Regular.otf │ │ │ │ │ └── font-override.css │ │ │ │ ├── lib/ │ │ │ │ │ └── main.coffee │ │ │ │ └── package.json │ │ │ ├── search-index/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── contact-search-indexer.es6 │ │ │ │ │ ├── event-search-indexer.es6 │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── thread-search-index-store.es6 │ │ │ │ └── package.json │ │ │ ├── send-and-archive/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── send-and-archive-extension.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── send-and-archive-spec.coffee │ │ │ │ └── styles/ │ │ │ │ └── send-and-archive.less │ │ │ ├── send-later/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── send-later-button.jsx │ │ │ │ │ ├── send-later-constants.es6 │ │ │ │ │ ├── send-later-popover.jsx │ │ │ │ │ └── send-later-status.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── send-later-button-spec.jsx │ │ │ │ │ └── send-later-popover-spec.jsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── send-later-used-modal.less │ │ │ │ └── send-later.less │ │ │ ├── send-reminders/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── send-reminders-account-sidebar-extension.es6 │ │ │ │ │ ├── send-reminders-composer-button.jsx │ │ │ │ │ ├── send-reminders-constants.es6 │ │ │ │ │ ├── send-reminders-headers.jsx │ │ │ │ │ ├── send-reminders-mailbox-perspective.es6 │ │ │ │ │ ├── send-reminders-popover-button.jsx │ │ │ │ │ ├── send-reminders-popover.jsx │ │ │ │ │ ├── send-reminders-query-subscription.es6 │ │ │ │ │ ├── send-reminders-store.es6 │ │ │ │ │ ├── send-reminders-thread-list-extension.es6 │ │ │ │ │ ├── send-reminders-thread-timestamp.jsx │ │ │ │ │ ├── send-reminders-toolbar-button.jsx │ │ │ │ │ └── send-reminders-utils.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ ├── reminders-used-modal.less │ │ │ │ └── send-reminders.less │ │ │ ├── sync-health-checker/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── sync-health-checker.es6 │ │ │ │ ├── package.json │ │ │ │ └── spec/ │ │ │ │ └── sync-health-checker-spec.es6 │ │ │ ├── system-tray/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ └── system-tray-icon-store.es6 │ │ │ │ ├── package.json │ │ │ │ └── spec/ │ │ │ │ └── system-tray-icon-store-spec.es6 │ │ │ ├── theme-picker/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.jsx │ │ │ │ │ ├── theme-option.jsx │ │ │ │ │ └── theme-picker.jsx │ │ │ │ ├── package.json │ │ │ │ ├── preview-styles/ │ │ │ │ │ └── theme-option.less │ │ │ │ ├── spec/ │ │ │ │ │ └── theme-picker-spec.jsx │ │ │ │ └── styles/ │ │ │ │ └── theme-picker.less │ │ │ ├── thread-list/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── category-removal-target-rulesets.es6 │ │ │ │ │ ├── injects-toolbar-buttons.jsx │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── message-list-toolbar.jsx │ │ │ │ │ ├── selected-items-stack.jsx │ │ │ │ │ ├── thread-list-columns.cjsx │ │ │ │ │ ├── thread-list-context-menu.es6 │ │ │ │ │ ├── thread-list-data-source.es6 │ │ │ │ │ ├── thread-list-icon.cjsx │ │ │ │ │ ├── thread-list-participants.cjsx │ │ │ │ │ ├── thread-list-quick-actions.cjsx │ │ │ │ │ ├── thread-list-scroll-tooltip.cjsx │ │ │ │ │ ├── thread-list-store.coffee │ │ │ │ │ ├── thread-list-toolbar.jsx │ │ │ │ │ ├── thread-list.cjsx │ │ │ │ │ └── thread-toolbar-buttons.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── category-removal-target-rulesets-spec.es6 │ │ │ │ │ ├── thread-list-column-spec.coffee │ │ │ │ │ ├── thread-list-participants-spec.cjsx │ │ │ │ │ ├── thread-list-spec.cjsx │ │ │ │ │ └── thread-toolbar-buttons-spec.cjsx │ │ │ │ └── stylesheets/ │ │ │ │ ├── selected-items-stack.less │ │ │ │ └── thread-list.less │ │ │ ├── thread-search/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── search-actions.es6 │ │ │ │ │ ├── search-mailbox-perspective.es6 │ │ │ │ │ ├── search-query-subscription.es6 │ │ │ │ │ ├── search-store.es6 │ │ │ │ │ └── thread-search-bar.jsx │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ └── search-bar-spec.cjsx │ │ │ │ └── stylesheets/ │ │ │ │ └── thread-search-bar.less │ │ │ ├── thread-sharing/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── copy-button.jsx │ │ │ │ │ ├── external-threads.es6 │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── thread-sharing-button.jsx │ │ │ │ │ ├── thread-sharing-constants.es6 │ │ │ │ │ └── thread-sharing-popover.jsx │ │ │ │ ├── package.json │ │ │ │ └── stylesheets/ │ │ │ │ └── main.less │ │ │ ├── thread-snooze/ │ │ │ │ ├── README.md │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── snooze-actions.es6 │ │ │ │ │ ├── snooze-buttons.jsx │ │ │ │ │ ├── snooze-constants.es6 │ │ │ │ │ ├── snooze-mail-label.jsx │ │ │ │ │ ├── snooze-popover.jsx │ │ │ │ │ ├── snooze-store.jsx │ │ │ │ │ └── snooze-utils.es6 │ │ │ │ ├── package.json │ │ │ │ ├── spec/ │ │ │ │ │ ├── snooze-store-spec.es6 │ │ │ │ │ └── snooze-utils-spec.es6 │ │ │ │ └── stylesheets/ │ │ │ │ ├── snooze-feature-used-modal.less │ │ │ │ ├── snooze-mail-label.less │ │ │ │ └── snooze-popover.less │ │ │ ├── ui-dark/ │ │ │ │ ├── LICENSE.md │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ ├── email-frame.less │ │ │ │ └── ui-variables.less │ │ │ ├── ui-darkside/ │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── index.less │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ ├── darkside-composer.less │ │ │ │ ├── darkside-drafts.less │ │ │ │ ├── darkside-inputs.less │ │ │ │ ├── darkside-labels.less │ │ │ │ ├── darkside-message-list.less │ │ │ │ ├── darkside-notifications.less │ │ │ │ ├── darkside-preferences.less │ │ │ │ ├── darkside-sidebar.less │ │ │ │ ├── darkside-swiping.less │ │ │ │ ├── darkside-thread-icons.less │ │ │ │ ├── darkside-threadlist.less │ │ │ │ ├── darkside-toolbars.less │ │ │ │ ├── darkside-variables.less │ │ │ │ ├── darkside-window-controls.less │ │ │ │ └── theme-colors.less │ │ │ ├── ui-less-is-more/ │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── index.less │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ ├── less-is-more.less │ │ │ │ └── theme-colors.less │ │ │ ├── ui-light/ │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ └── ui-variables.less │ │ │ ├── ui-taiga/ │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ ├── controls.less │ │ │ │ ├── email-frame.less │ │ │ │ ├── notifications.less │ │ │ │ ├── sidebar.less │ │ │ │ ├── theme-colors.less │ │ │ │ ├── threads.less │ │ │ │ ├── ui-variables.less │ │ │ │ └── variables.less │ │ │ ├── ui-ubuntu/ │ │ │ │ ├── README.md │ │ │ │ ├── index.less │ │ │ │ ├── package.json │ │ │ │ └── styles/ │ │ │ │ ├── theme-colors.less │ │ │ │ └── ui-variables.less │ │ │ ├── undo-redo/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── main.es6 │ │ │ │ │ ├── undo-redo-thread-list-toast.jsx │ │ │ │ │ ├── undo-send-store.es6 │ │ │ │ │ └── undo-send-toast.jsx │ │ │ │ └── package.json │ │ │ ├── unread-notifications/ │ │ │ │ ├── lib/ │ │ │ │ │ └── main.es6 │ │ │ │ ├── package.json │ │ │ │ └── spec/ │ │ │ │ └── main-spec.es6 │ │ │ ├── verify-install-location/ │ │ │ │ ├── lib/ │ │ │ │ │ └── main.es6 │ │ │ │ └── package.json │ │ │ └── worker-ui/ │ │ │ ├── lib/ │ │ │ │ ├── developer-bar-curl-item.cjsx │ │ │ │ ├── developer-bar-long-poll-item.cjsx │ │ │ │ ├── developer-bar-store.coffee │ │ │ │ ├── developer-bar-task.cjsx │ │ │ │ ├── developer-bar.cjsx │ │ │ │ └── main.cjsx │ │ │ ├── package.json │ │ │ └── stylesheets/ │ │ │ └── worker-ui.less │ │ ├── keymaps/ │ │ │ ├── README.m │ │ │ ├── base-darwin.json │ │ │ ├── base-linux.json │ │ │ ├── base-win32.json │ │ │ ├── base.json │ │ │ └── templates/ │ │ │ ├── Apple Mail.json │ │ │ ├── Gmail.json │ │ │ ├── Inbox by Gmail.json │ │ │ └── Outlook.json │ │ ├── menus/ │ │ │ ├── darwin.json │ │ │ ├── linux.json │ │ │ └── win32.json │ │ ├── package.json │ │ ├── script/ │ │ │ ├── grunt │ │ │ ├── grunt.cmd │ │ │ ├── mkdeb │ │ │ ├── mkrpm │ │ │ ├── publish-docs │ │ │ └── utils/ │ │ │ └── child-process-wrapper.js │ │ ├── spec/ │ │ │ ├── action-bridge-spec.coffee │ │ │ ├── async-test-spec.es6 │ │ │ ├── buffered-process-spec.coffee │ │ │ ├── components/ │ │ │ │ ├── blockquote-manager-spec.es6 │ │ │ │ ├── clipboard-service-spec.coffee │ │ │ │ ├── contenteditable-component-spec.cjsx │ │ │ │ ├── date-input-spec.jsx │ │ │ │ ├── date-picker-popover-spec.jsx │ │ │ │ ├── editable-list-spec.jsx │ │ │ │ ├── editable-table-spec.jsx │ │ │ │ ├── evented-iframe-spec.cjsx │ │ │ │ ├── fixed-popover-spec.jsx │ │ │ │ ├── injected-component-set-spec.jsx │ │ │ │ ├── multiselect-dropdown-spec.jsx │ │ │ │ ├── multiselect-list-interaction-handler-spec.coffee │ │ │ │ ├── multiselect-split-interaction-handler-spec.coffee │ │ │ │ ├── nylas-calendar/ │ │ │ │ │ ├── calendar-toggles-spec.jsx │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ └── events.es6 │ │ │ │ │ ├── test-data-source.es6 │ │ │ │ │ ├── test-utils.es6 │ │ │ │ │ ├── week-view-extended-spec.jsx │ │ │ │ │ └── week-view-spec.jsx │ │ │ │ ├── participants-text-field-spec.jsx │ │ │ │ ├── selectable-table-spec.jsx │ │ │ │ ├── table/ │ │ │ │ │ ├── table-data-source-spec.jsx │ │ │ │ │ └── table-spec.jsx │ │ │ │ └── tokenizing-text-field-spec.cjsx │ │ │ ├── database-object-registry-spec.es6 │ │ │ ├── default-client-helper-spec.coffee │ │ │ ├── fixtures/ │ │ │ │ ├── css.css │ │ │ │ ├── db-test-model.coffee │ │ │ │ ├── emails/ │ │ │ │ │ ├── correct_sig.txt │ │ │ │ │ ├── email_1.html │ │ │ │ │ ├── email_10.html │ │ │ │ │ ├── email_10_stripped.html │ │ │ │ │ ├── email_11.html │ │ │ │ │ ├── email_11_stripped.html │ │ │ │ │ ├── email_12.html │ │ │ │ │ ├── email_12_stripped.html │ │ │ │ │ ├── email_13.html │ │ │ │ │ ├── email_13_stripped.html │ │ │ │ │ ├── email_14.html │ │ │ │ │ ├── email_14_stripped.html │ │ │ │ │ ├── email_15.html │ │ │ │ │ ├── email_15_stripped.html │ │ │ │ │ ├── email_16.html │ │ │ │ │ ├── email_16_stripped.html │ │ │ │ │ ├── email_17.html │ │ │ │ │ ├── email_17_stripped.html │ │ │ │ │ ├── email_18.html │ │ │ │ │ ├── email_18_stripped.html │ │ │ │ │ ├── email_19.html │ │ │ │ │ ├── email_19_stripped.html │ │ │ │ │ ├── email_1_1.txt │ │ │ │ │ ├── email_1_2.txt │ │ │ │ │ ├── email_1_3.txt │ │ │ │ │ ├── email_1_4.txt │ │ │ │ │ ├── email_1_5.txt │ │ │ │ │ ├── email_1_6.txt │ │ │ │ │ ├── email_1_7.txt │ │ │ │ │ ├── email_1_8.txt │ │ │ │ │ ├── email_1_stripped.html │ │ │ │ │ ├── email_2.html │ │ │ │ │ ├── email_20.html │ │ │ │ │ ├── email_20_stripped.html │ │ │ │ │ ├── email_21.html │ │ │ │ │ ├── email_21_stripped.html │ │ │ │ │ ├── email_22.html │ │ │ │ │ ├── email_22_stripped.html │ │ │ │ │ ├── email_23.html │ │ │ │ │ ├── email_23_stripped.html │ │ │ │ │ ├── email_2_1.txt │ │ │ │ │ ├── email_2_stripped.html │ │ │ │ │ ├── email_3.html │ │ │ │ │ ├── email_3_stripped.html │ │ │ │ │ ├── email_4.html │ │ │ │ │ ├── email_4_stripped.html │ │ │ │ │ ├── email_5.html │ │ │ │ │ ├── email_5_stripped.html │ │ │ │ │ ├── email_6.html │ │ │ │ │ ├── email_6_stripped.html │ │ │ │ │ ├── email_7.html │ │ │ │ │ ├── email_7_stripped.html │ │ │ │ │ ├── email_8.html │ │ │ │ │ ├── email_8_stripped.html │ │ │ │ │ ├── email_9.html │ │ │ │ │ ├── email_9_stripped.html │ │ │ │ │ ├── email_BlackBerry.txt │ │ │ │ │ ├── email_bullets.txt │ │ │ │ │ ├── email_iPhone.txt │ │ │ │ │ ├── email_multi_word_sent_from_my_mobile_device.txt │ │ │ │ │ └── email_sent_from_my_not_signature.txt │ │ │ │ ├── module-cache/ │ │ │ │ │ └── file.json │ │ │ │ ├── packages/ │ │ │ │ │ ├── package-that-throws-an-exception/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-that-throws-on-activate/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-that-throws-on-deactivate/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-broken-keymap/ │ │ │ │ │ │ └── keymaps/ │ │ │ │ │ │ └── broken.json │ │ │ │ │ ├── package-with-broken-package-json/ │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-config-defaults/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-config-schema/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-deactivate/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-deprecated-pane-item-method/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-empty-activation-commands/ │ │ │ │ │ │ ├── index.coffee │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-empty-keymap/ │ │ │ │ │ │ ├── keymaps/ │ │ │ │ │ │ │ └── keymap.cson │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-empty-menu/ │ │ │ │ │ │ ├── menus/ │ │ │ │ │ │ │ └── menu.cson │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-incompatible-native-module/ │ │ │ │ │ │ ├── main.js │ │ │ │ │ │ ├── node_modules/ │ │ │ │ │ │ │ └── native-module/ │ │ │ │ │ │ │ ├── build/ │ │ │ │ │ │ │ │ └── Release/ │ │ │ │ │ │ │ │ └── native.node │ │ │ │ │ │ │ ├── main.js │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-index/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-invalid-styles/ │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ └── index.less │ │ │ │ │ ├── package-with-keymaps/ │ │ │ │ │ │ └── keymaps/ │ │ │ │ │ │ ├── keymap-1.json │ │ │ │ │ │ └── keymap-2.json │ │ │ │ │ ├── package-with-keymaps-manifest/ │ │ │ │ │ │ ├── keymaps/ │ │ │ │ │ │ │ ├── keymap-1.json │ │ │ │ │ │ │ └── keymap-2.json │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-main/ │ │ │ │ │ │ ├── main-module.coffee │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-menus/ │ │ │ │ │ │ └── menus/ │ │ │ │ │ │ ├── menu-1.json │ │ │ │ │ │ └── menu-2.json │ │ │ │ │ ├── package-with-menus-manifest/ │ │ │ │ │ │ ├── menus/ │ │ │ │ │ │ │ ├── menu-1.json │ │ │ │ │ │ │ └── menu-2.json │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-models/ │ │ │ │ │ │ ├── main-module.coffee │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-serialization/ │ │ │ │ │ │ └── index.coffee │ │ │ │ │ ├── package-with-serialize-error/ │ │ │ │ │ │ ├── index.coffee │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-with-style-sheets-manifest/ │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ ├── 1.css │ │ │ │ │ │ ├── 2.less │ │ │ │ │ │ └── 3.css │ │ │ │ │ ├── package-with-styles/ │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ ├── 1.css │ │ │ │ │ │ ├── 2.less │ │ │ │ │ │ ├── 3.test-context.css │ │ │ │ │ │ └── 4.css │ │ │ │ │ ├── package-with-stylesheets-manifest/ │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── package-without-module/ │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── theme-with-incomplete-ui-variables/ │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ ├── editor.less │ │ │ │ │ │ └── ui-variables.less │ │ │ │ │ ├── theme-with-index-css/ │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── theme-with-index-less/ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── theme-with-invalid-styles/ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── package.json │ │ │ │ │ ├── theme-with-package-file/ │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ ├── first.css │ │ │ │ │ │ ├── last.css │ │ │ │ │ │ └── second.less │ │ │ │ │ ├── theme-with-ui-variables/ │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles/ │ │ │ │ │ │ ├── editor.less │ │ │ │ │ │ └── ui-variables.less │ │ │ │ │ └── theme-without-package-file/ │ │ │ │ │ └── styles/ │ │ │ │ │ ├── a.css │ │ │ │ │ ├── b.css │ │ │ │ │ ├── c.less │ │ │ │ │ └── d.csv │ │ │ │ ├── paste/ │ │ │ │ │ ├── excel-paste-in.html │ │ │ │ │ ├── excel-paste-out.html │ │ │ │ │ ├── word-paste-in.html │ │ │ │ │ └── word-paste-out.html │ │ │ │ ├── sample-deltas-clustered.json │ │ │ │ ├── sample-deltas.json │ │ │ │ ├── sample.less │ │ │ │ ├── table-data.es6 │ │ │ │ └── task-spec-handler.coffee │ │ │ ├── list-selection-spec.coffee │ │ │ ├── mail-rules-processor-spec.coffee │ │ │ ├── mailbox-perspective-spec.es6 │ │ │ ├── menu-manager-spec.coffee │ │ │ ├── models/ │ │ │ │ ├── category-spec.coffee │ │ │ │ ├── contact-spec.coffee │ │ │ │ ├── event-spec.coffee │ │ │ │ ├── file-spec.coffee │ │ │ │ ├── message-spec.coffee │ │ │ │ ├── model-spec.es6 │ │ │ │ ├── model-with-metadata-spec.es6 │ │ │ │ ├── mutable-query-result-set-spec.es6 │ │ │ │ ├── query-range-spec.es6 │ │ │ │ ├── query-spec.es6 │ │ │ │ ├── query-subscription-pool-spec.es6 │ │ │ │ ├── query-subscription-spec.es6 │ │ │ │ └── thread-spec.coffee │ │ │ ├── module-cache-spec.coffee │ │ │ ├── n1-spec-runner/ │ │ │ │ ├── console-reporter.es6 │ │ │ │ ├── jasmine-extensions.es6 │ │ │ │ ├── jasmine.js │ │ │ │ ├── master-after-each.es6 │ │ │ │ ├── master-before-each.es6 │ │ │ │ ├── n1-gui-reporter.cjsx │ │ │ │ ├── n1-spec-loader.es6 │ │ │ │ ├── n1-spec-runner.es6 │ │ │ │ ├── nylas-test-constants.es6 │ │ │ │ ├── react-test-utils-extensions.es6 │ │ │ │ ├── spec-bootstrap.es6 │ │ │ │ ├── terminal-reporter.es6 │ │ │ │ ├── time-override.coffee │ │ │ │ └── time-reporter.coffee │ │ │ ├── nylas-api-spec.coffee │ │ │ ├── nylas-env-spec.es6 │ │ │ ├── nylas-protocol-handler-spec.es6 │ │ │ ├── nylas-test-utils.coffee │ │ │ ├── package-manager-spec.coffee │ │ │ ├── package-spec.coffee │ │ │ ├── registries/ │ │ │ │ ├── component-registry-spec.coffee │ │ │ │ └── extension-registry-spec.coffee │ │ │ ├── services/ │ │ │ │ ├── delta-processor-spec.coffee │ │ │ │ ├── delta-streaming-connection-spec.coffee │ │ │ │ ├── inline-style-transformer-spec.coffee │ │ │ │ ├── quoted-html-transformer-spec.coffee │ │ │ │ ├── quoted-plain-text-transformer-spec.coffee │ │ │ │ └── search/ │ │ │ │ ├── search-query-backend-imap-spec.es6 │ │ │ │ └── search-query-parser-spec.es6 │ │ │ ├── spellchecker-spec.es6 │ │ │ ├── stores/ │ │ │ │ ├── account-store-spec.coffee │ │ │ │ ├── badge-store-spec.coffee │ │ │ │ ├── contact-store-spec.coffee │ │ │ │ ├── database-setup-query-builder-spec.es6 │ │ │ │ ├── database-store-spec.es6 │ │ │ │ ├── database-transaction-spec.es6 │ │ │ │ ├── draft-editing-session-spec.coffee │ │ │ │ ├── draft-factory-spec.es6 │ │ │ │ ├── draft-helpers-spec.es6 │ │ │ │ ├── draft-store-spec.es6 │ │ │ │ ├── feature-usage-store-spec.es6 │ │ │ │ ├── file-download-store-spec.coffee │ │ │ │ ├── file-upload-store-spec.coffee │ │ │ │ ├── focused-contacts-store-spec.coffee │ │ │ │ ├── focused-content-store-spec.coffee │ │ │ │ ├── focused-perspective-store-spec.coffee │ │ │ │ ├── folder-sync-progress-store-spec.es6 │ │ │ │ ├── identity-store-spec.es6 │ │ │ │ ├── message-store-spec.coffee │ │ │ │ ├── send-actions-store-spec.es6 │ │ │ │ ├── task-queue-spec.coffee │ │ │ │ ├── task-subclass.es6 │ │ │ │ └── undo-redo-store-spec.es6 │ │ │ ├── tasks/ │ │ │ │ ├── base-draft-task-spec.es6 │ │ │ │ ├── change-folder-task-spec.coffee │ │ │ │ ├── change-labels-task-spec.coffee │ │ │ │ ├── change-mail-task-spec.coffee │ │ │ │ ├── change-starred-task-spec.coffee │ │ │ │ ├── change-unread-task-spec.coffee │ │ │ │ ├── destroy-category-task-spec.coffee │ │ │ │ ├── destroy-model-task-spec.es6 │ │ │ │ ├── event-rsvp-task-spec.coffee │ │ │ │ ├── send-draft-task-spec.es6 │ │ │ │ ├── syncback-category-task-spec.coffee │ │ │ │ ├── syncback-metadata-task-spec.es6 │ │ │ │ ├── syncback-model-task-spec.es6 │ │ │ │ ├── task-factory-spec.es6 │ │ │ │ └── task-spec.coffee │ │ │ ├── themes/ │ │ │ │ ├── style-manager-spec.coffee │ │ │ │ ├── styles-element-spec.coffee │ │ │ │ └── theme-manager-spec.coffee │ │ │ ├── undo-stack-spec.es6 │ │ │ └── utils/ │ │ │ ├── date-utils-spec.es6 │ │ │ ├── dom-utils-spec.coffee │ │ │ └── utils-spec.coffee │ │ ├── src/ │ │ │ ├── apm-wrapper.coffee │ │ │ ├── browser/ │ │ │ │ ├── application-menu.coffee │ │ │ │ ├── application.es6 │ │ │ │ ├── config-migrator.es6 │ │ │ │ ├── config-persistence-manager.es6 │ │ │ │ ├── database-reader.es6 │ │ │ │ ├── file-list-cache.es6 │ │ │ │ ├── global-timer.es6 │ │ │ │ ├── linux-updater-adapter.es6 │ │ │ │ ├── main.js │ │ │ │ ├── nylas-protocol-handler.es6 │ │ │ │ ├── nylas-window.coffee │ │ │ │ ├── package-migration-manager.es6 │ │ │ │ ├── prevent-legacy-n1-migration.es6 │ │ │ │ ├── system-tray-manager.es6 │ │ │ │ ├── window-launcher.es6 │ │ │ │ ├── window-manager.es6 │ │ │ │ ├── windows-updater-squirrel-adapter.coffee │ │ │ │ └── windows-updater.js │ │ │ ├── buffered-process.coffee │ │ │ ├── canvas-utils.coffee │ │ │ ├── chaos-monkey.coffee │ │ │ ├── chrome-user-agent-stylesheet-string.coffee │ │ │ ├── color.coffee │ │ │ ├── compile-cache.js │ │ │ ├── compile-support/ │ │ │ │ ├── babel.js │ │ │ │ ├── cjsx.js │ │ │ │ ├── coffee-script.js │ │ │ │ └── typescript.js │ │ │ ├── components/ │ │ │ │ ├── attachment-items.jsx │ │ │ │ ├── billing-modal.jsx │ │ │ │ ├── bolded-search-result.jsx │ │ │ │ ├── button-dropdown.cjsx │ │ │ │ ├── code-snippet.jsx │ │ │ │ ├── config-prop-container.jsx │ │ │ │ ├── contenteditable/ │ │ │ │ │ ├── blockquote-manager.es6 │ │ │ │ │ ├── clipboard-service.es6 │ │ │ │ │ ├── contenteditable-service.es6 │ │ │ │ │ ├── contenteditable.cjsx │ │ │ │ │ ├── dom-normalizer.coffee │ │ │ │ │ ├── editor-api.coffee │ │ │ │ │ ├── emphasis-formatting-extension.es6 │ │ │ │ │ ├── exported-selection.es6 │ │ │ │ │ ├── extended-selection.coffee │ │ │ │ │ ├── floating-toolbar.cjsx │ │ │ │ │ ├── link-editor.cjsx │ │ │ │ │ ├── link-manager.es6 │ │ │ │ │ ├── list-manager.es6 │ │ │ │ │ ├── mouse-service.es6 │ │ │ │ │ ├── paragraph-formatting-extension.es6 │ │ │ │ │ ├── tab-manager.es6 │ │ │ │ │ ├── toolbar-button-manager.es6 │ │ │ │ │ └── toolbar-buttons.jsx │ │ │ │ ├── date-input.jsx │ │ │ │ ├── date-picker-popover.jsx │ │ │ │ ├── date-picker.jsx │ │ │ │ ├── decorators/ │ │ │ │ │ ├── auto-focuses.jsx │ │ │ │ │ ├── compose.es6 │ │ │ │ │ ├── has-tutorial-tip.jsx │ │ │ │ │ ├── listens-to-flux-store.jsx │ │ │ │ │ ├── listens-to-movement-keys.jsx │ │ │ │ │ └── listens-to-observable.jsx │ │ │ │ ├── disclosure-triangle.cjsx │ │ │ │ ├── drop-zone.jsx │ │ │ │ ├── dropdown-menu.jsx │ │ │ │ ├── editable-list.jsx │ │ │ │ ├── editable-table.jsx │ │ │ │ ├── empty-list-state.cjsx │ │ │ │ ├── evented-iframe.cjsx │ │ │ │ ├── feature-used-up-modal.jsx │ │ │ │ ├── fixed-popover.jsx │ │ │ │ ├── flexbox.jsx │ │ │ │ ├── flux-container.jsx │ │ │ │ ├── focus-container.jsx │ │ │ │ ├── generated-form.cjsx │ │ │ │ ├── injected-component-label.jsx │ │ │ │ ├── injected-component-set.cjsx │ │ │ │ ├── injected-component.cjsx │ │ │ │ ├── key-commands-region.jsx │ │ │ │ ├── lazy-rendered-list.jsx │ │ │ │ ├── list-data-source.es6 │ │ │ │ ├── list-selection.es6 │ │ │ │ ├── list-tabular-item.cjsx │ │ │ │ ├── list-tabular.jsx │ │ │ │ ├── mail-important-icon.cjsx │ │ │ │ ├── mail-label-set.jsx │ │ │ │ ├── mail-label.jsx │ │ │ │ ├── menu.cjsx │ │ │ │ ├── metadata-composer-toggle-button.jsx │ │ │ │ ├── modal.jsx │ │ │ │ ├── multiselect-action-bar.cjsx │ │ │ │ ├── multiselect-dropdown.jsx │ │ │ │ ├── multiselect-list-interaction-handler.coffee │ │ │ │ ├── multiselect-list.cjsx │ │ │ │ ├── multiselect-split-interaction-handler.coffee │ │ │ │ ├── multiselect-toolbar.jsx │ │ │ │ ├── notification.jsx │ │ │ │ ├── nylas-calendar/ │ │ │ │ │ ├── calendar-constants.es6 │ │ │ │ │ ├── calendar-data-source.es6 │ │ │ │ │ ├── calendar-event-container.jsx │ │ │ │ │ ├── calendar-event-popover.jsx │ │ │ │ │ ├── calendar-event.jsx │ │ │ │ │ ├── calendar-helpers.jsx │ │ │ │ │ ├── calendar-toggles.jsx │ │ │ │ │ ├── current-time-indicator.jsx │ │ │ │ │ ├── event-grid-background.jsx │ │ │ │ │ ├── event-participants-input.jsx │ │ │ │ │ ├── event-search-bar.jsx │ │ │ │ │ ├── footer-controls.jsx │ │ │ │ │ ├── header-controls.jsx │ │ │ │ │ ├── mini-month-view.jsx │ │ │ │ │ ├── month-view.jsx │ │ │ │ │ ├── nylas-calendar.jsx │ │ │ │ │ ├── top-banner.jsx │ │ │ │ │ ├── week-view-all-day-events.jsx │ │ │ │ │ ├── week-view-event-column.jsx │ │ │ │ │ └── week-view.jsx │ │ │ │ ├── oauth-signin-page.jsx │ │ │ │ ├── open-identity-page-button.jsx │ │ │ │ ├── outline-view-item.jsx │ │ │ │ ├── outline-view.jsx │ │ │ │ ├── overlaid-components/ │ │ │ │ │ ├── anchor-constants.es6 │ │ │ │ │ ├── custom-contenteditable-components.es6 │ │ │ │ │ ├── overlaid-components.jsx │ │ │ │ │ └── overlaid-composer-extension.es6 │ │ │ │ ├── participants-text-field.jsx │ │ │ │ ├── resizable-region.cjsx │ │ │ │ ├── retina-img.jsx │ │ │ │ ├── scenario-editor-models.es6 │ │ │ │ ├── scenario-editor-row.cjsx │ │ │ │ ├── scenario-editor.cjsx │ │ │ │ ├── scroll-region.cjsx │ │ │ │ ├── scrollbar-ticks.jsx │ │ │ │ ├── search-bar.jsx │ │ │ │ ├── selectable-table.jsx │ │ │ │ ├── spinner.cjsx │ │ │ │ ├── swipe-container.jsx │ │ │ │ ├── switch.jsx │ │ │ │ ├── syncing-list-state.jsx │ │ │ │ ├── tab-group-region.cjsx │ │ │ │ ├── table/ │ │ │ │ │ ├── table-data-source.es6 │ │ │ │ │ └── table.jsx │ │ │ │ ├── time-picker.jsx │ │ │ │ ├── toast.jsx │ │ │ │ ├── tokenizing-text-field.jsx │ │ │ │ ├── undo-toast.jsx │ │ │ │ ├── unsafe-component.cjsx │ │ │ │ └── webview.jsx │ │ │ ├── config-schema.es6 │ │ │ ├── config-utils.js │ │ │ ├── config.coffee │ │ │ ├── database-helpers.es6 │ │ │ ├── date-utils.es6 │ │ │ ├── decorators/ │ │ │ │ └── inflates-draft-client-id.jsx │ │ │ ├── default-client-helper.coffee │ │ │ ├── deprecate-utils.coffee │ │ │ ├── dom-utils.coffee │ │ │ ├── dom-walkers.es6 │ │ │ ├── error-logger-extensions/ │ │ │ │ └── nylas-private-error-reporter.js │ │ │ ├── error-logger.js │ │ │ ├── extensions/ │ │ │ │ ├── account-sidebar-extension.es6 │ │ │ │ ├── composer-extension.coffee │ │ │ │ ├── contenteditable-extension.coffee │ │ │ │ ├── extension-utils.es6 │ │ │ │ ├── message-view-extension.coffee │ │ │ │ └── thread-list-extension.es6 │ │ │ ├── flux/ │ │ │ │ ├── action-bridge.es6 │ │ │ │ ├── actions.es6 │ │ │ │ ├── attributes/ │ │ │ │ │ ├── attribute-boolean.es6 │ │ │ │ │ ├── attribute-collection.es6 │ │ │ │ │ ├── attribute-datetime.es6 │ │ │ │ │ ├── attribute-joined-data.es6 │ │ │ │ │ ├── attribute-number.es6 │ │ │ │ │ ├── attribute-object.es6 │ │ │ │ │ ├── attribute-serverid.es6 │ │ │ │ │ ├── attribute-string.es6 │ │ │ │ │ ├── attribute.es6 │ │ │ │ │ ├── matcher.es6 │ │ │ │ │ └── sort-order.es6 │ │ │ │ ├── attributes.es6 │ │ │ │ ├── coffee-helpers.coffee │ │ │ │ ├── errors.es6 │ │ │ │ ├── models/ │ │ │ │ │ ├── account.es6 │ │ │ │ │ ├── calendar.es6 │ │ │ │ │ ├── category.es6 │ │ │ │ │ ├── contact.es6 │ │ │ │ │ ├── event.es6 │ │ │ │ │ ├── file.es6 │ │ │ │ │ ├── folder.es6 │ │ │ │ │ ├── json-blob.es6 │ │ │ │ │ ├── label.es6 │ │ │ │ │ ├── message-utils.es6 │ │ │ │ │ ├── message.es6 │ │ │ │ │ ├── model-with-metadata.es6 │ │ │ │ │ ├── model.coffee │ │ │ │ │ ├── mutable-query-result-set.es6 │ │ │ │ │ ├── mutable-query-subscription.es6 │ │ │ │ │ ├── provider-syncback-request.es6 │ │ │ │ │ ├── query-range.es6 │ │ │ │ │ ├── query-result-set.es6 │ │ │ │ │ ├── query-subscription-pool.es6 │ │ │ │ │ ├── query-subscription.es6 │ │ │ │ │ ├── query.es6 │ │ │ │ │ ├── thread.es6 │ │ │ │ │ ├── unread-query-subscription.es6 │ │ │ │ │ └── utils.coffee │ │ │ │ ├── modules/ │ │ │ │ │ └── reflux-coffee.coffee │ │ │ │ ├── nylas-api-helpers.es6 │ │ │ │ ├── nylas-api-request.es6 │ │ │ │ ├── nylas-api.es6 │ │ │ │ ├── nylas-long-connection.es6 │ │ │ │ ├── stores/ │ │ │ │ │ ├── account-store.es6 │ │ │ │ │ ├── badge-store.es6 │ │ │ │ │ ├── category-store.coffee │ │ │ │ │ ├── contact-ranking-store.coffee │ │ │ │ │ ├── contact-store.coffee │ │ │ │ │ ├── database-agent.js │ │ │ │ │ ├── database-change-record.es6 │ │ │ │ │ ├── database-setup-query-builder.es6 │ │ │ │ │ ├── database-store.es6 │ │ │ │ │ ├── database-writer.es6 │ │ │ │ │ ├── delta-connection-store.es6 │ │ │ │ │ ├── draft-editing-session.coffee │ │ │ │ │ ├── draft-factory.coffee │ │ │ │ │ ├── draft-helpers.es6 │ │ │ │ │ ├── draft-store-extension.coffee │ │ │ │ │ ├── draft-store.es6 │ │ │ │ │ ├── feature-usage-store.jsx │ │ │ │ │ ├── file-download-store.es6 │ │ │ │ │ ├── file-upload-store.es6 │ │ │ │ │ ├── focused-contacts-store.es6 │ │ │ │ │ ├── focused-content-store.coffee │ │ │ │ │ ├── focused-perspective-store.es6 │ │ │ │ │ ├── folder-sync-progress-store.es6 │ │ │ │ │ ├── identity-store.es6 │ │ │ │ │ ├── mail-rules-store.coffee │ │ │ │ │ ├── message-body-processor.es6 │ │ │ │ │ ├── message-store-extension.coffee │ │ │ │ │ ├── message-store.coffee │ │ │ │ │ ├── metadata-store.es6 │ │ │ │ │ ├── modal-store.jsx │ │ │ │ │ ├── observable-list-data-source.es6 │ │ │ │ │ ├── online-status-store.es6 │ │ │ │ │ ├── outbox-store.es6 │ │ │ │ │ ├── popover-store.jsx │ │ │ │ │ ├── preferences-ui-store.es6 │ │ │ │ │ ├── recently-read-store.es6 │ │ │ │ │ ├── searchable-component-store.es6 │ │ │ │ │ ├── send-actions-store.es6 │ │ │ │ │ ├── signature-store.es6 │ │ │ │ │ ├── task-queue-status-store.coffee │ │ │ │ │ ├── task-queue.coffee │ │ │ │ │ ├── thread-counts-store.coffee │ │ │ │ │ ├── thread-list-actions-store.es6 │ │ │ │ │ ├── undo-redo-store.es6 │ │ │ │ │ └── workspace-store.coffee │ │ │ │ ├── syncback-task-api-request.es6 │ │ │ │ └── tasks/ │ │ │ │ ├── base-draft-task.es6 │ │ │ │ ├── change-folder-task.es6 │ │ │ │ ├── change-labels-task.es6 │ │ │ │ ├── change-mail-task.es6 │ │ │ │ ├── change-starred-task.es6 │ │ │ │ ├── change-unread-task.es6 │ │ │ │ ├── destroy-category-task.es6 │ │ │ │ ├── destroy-draft-task.es6 │ │ │ │ ├── destroy-model-task.es6 │ │ │ │ ├── ensure-message-in-sent-folder-task.es6 │ │ │ │ ├── event-rsvp-task.es6 │ │ │ │ ├── perform-send-action-task.es6 │ │ │ │ ├── reprocess-mail-rules-task.es6 │ │ │ │ ├── send-draft-task.es6 │ │ │ │ ├── send-feature-usage-event-task.es6 │ │ │ │ ├── syncback-category-task.es6 │ │ │ │ ├── syncback-event-task.es6 │ │ │ │ ├── syncback-metadata-task.es6 │ │ │ │ ├── syncback-model-task.es6 │ │ │ │ ├── task-factory.es6 │ │ │ │ └── task.es6 │ │ │ ├── fs-utils.es6 │ │ │ ├── global/ │ │ │ │ ├── nylas-component-kit.coffee │ │ │ │ ├── nylas-exports.es6 │ │ │ │ ├── nylas-observables.coffee │ │ │ │ └── nylas-store.coffee │ │ │ ├── key-manager.es6 │ │ │ ├── keymap-manager.es6 │ │ │ ├── less-compile-cache.es6 │ │ │ ├── mail-rules-processor.coffee │ │ │ ├── mail-rules-templates.coffee │ │ │ ├── mailbox-perspective.coffee │ │ │ ├── menu-helpers.coffee │ │ │ ├── menu-manager.es6 │ │ │ ├── module-cache.coffee │ │ │ ├── multi-request-progress-monitor.es6 │ │ │ ├── n1-cloud-api.es6 │ │ │ ├── native-notifications.es6 │ │ │ ├── nylas-env.es6 │ │ │ ├── package-manager.coffee │ │ │ ├── package.coffee │ │ │ ├── priority-ui-coordinator.es6 │ │ │ ├── regexp-utils.coffee │ │ │ ├── registries/ │ │ │ │ ├── command-registry.es6 │ │ │ │ ├── component-registry.coffee │ │ │ │ ├── database-object-registry.es6 │ │ │ │ ├── extension-registry.es6 │ │ │ │ ├── serializable-registry.es6 │ │ │ │ ├── service-registry.es6 │ │ │ │ ├── sound-registry.coffee │ │ │ │ ├── store-registry.es6 │ │ │ │ └── task-registry.es6 │ │ │ ├── searchable-components/ │ │ │ │ ├── iframe-searcher.es6 │ │ │ │ ├── real-dom-parser.es6 │ │ │ │ ├── search-constants.es6 │ │ │ │ ├── search-match.jsx │ │ │ │ ├── searchable-component-maker.jsx │ │ │ │ ├── unified-dom-parser.es6 │ │ │ │ └── virtual-dom-parser.es6 │ │ │ ├── secondary-window-bootstrap.es6 │ │ │ ├── services/ │ │ │ │ ├── battery-status-manager.es6 │ │ │ │ ├── delta-processor.es6 │ │ │ │ ├── delta-streaming-connection.es6 │ │ │ │ ├── inline-style-transformer.es6 │ │ │ │ ├── model-search-indexer.es6 │ │ │ │ ├── quote-string-detector.es6 │ │ │ │ ├── quoted-html-transformer.es6 │ │ │ │ ├── quoted-plain-text-transformer.coffee │ │ │ │ ├── sanitize-transformer.es6 │ │ │ │ ├── search/ │ │ │ │ │ ├── search-query-ast.es6 │ │ │ │ │ ├── search-query-backend-imap.es6 │ │ │ │ │ ├── search-query-backend-local.es6 │ │ │ │ │ └── search-query-parser.es6 │ │ │ │ ├── search-index-scheduler.es6 │ │ │ │ └── unwrapped-signature-detector.es6 │ │ │ ├── sheet-container.cjsx │ │ │ ├── sheet-toolbar.cjsx │ │ │ ├── sheet.cjsx │ │ │ ├── spellchecker.es6 │ │ │ ├── style-manager.coffee │ │ │ ├── styles-element.coffee │ │ │ ├── system-start-service.es6 │ │ │ ├── task-bootstrap.coffee │ │ │ ├── task.coffee │ │ │ ├── theme-manager.coffee │ │ │ ├── theme-package.coffee │ │ │ ├── undo-stack.es6 │ │ │ ├── virtual-dom-utils.es6 │ │ │ ├── window-bootstrap.es6 │ │ │ ├── window-bridge.coffee │ │ │ ├── window-event-handler.coffee │ │ │ └── window.coffee │ │ └── static/ │ │ ├── animations/ │ │ │ └── inbox-zero/ │ │ │ ├── airstrip/ │ │ │ │ ├── airstrip.html │ │ │ │ └── airstrip.hyperesources/ │ │ │ │ ├── 96CD36-restorable.plist │ │ │ │ ├── PIE.htc │ │ │ │ └── airstrip_hype_generated_script.js │ │ │ ├── galaxy/ │ │ │ │ ├── galaxy.html │ │ │ │ └── galaxy.hyperesources/ │ │ │ │ ├── BC8A15-restorable.plist │ │ │ │ ├── PIE.htc │ │ │ │ └── galaxy_hype_generated_script.js │ │ │ ├── gem/ │ │ │ │ ├── gem.html │ │ │ │ └── gem.hyperesources/ │ │ │ │ └── gemslower_hype_generated_script.js │ │ │ ├── oasis/ │ │ │ │ ├── oasis.html │ │ │ │ └── oasis.hyperesources/ │ │ │ │ ├── DC9C02-restorable.plist │ │ │ │ ├── PIE.htc │ │ │ │ └── oasis_hype_generated_script.js │ │ │ └── tron/ │ │ │ ├── tron.html │ │ │ └── tron.hyperesources/ │ │ │ ├── 4982A5-restorable.plist │ │ │ ├── PIE.htc │ │ │ └── tron_hype_generated_script.js │ │ ├── buttons.less │ │ ├── components/ │ │ │ ├── attachment-items.less │ │ │ ├── billing-modal.less │ │ │ ├── button-dropdown.less │ │ │ ├── code-snippet.less │ │ │ ├── contenteditable.less │ │ │ ├── date-input.less │ │ │ ├── date-picker-popover.less │ │ │ ├── date-picker.less │ │ │ ├── disclosure-triangle.less │ │ │ ├── editable-list.less │ │ │ ├── editable-table.less │ │ │ ├── empty-list-state.less │ │ │ ├── extra.less │ │ │ ├── feature-used-up-modal.less │ │ │ ├── fixed-popover.less │ │ │ ├── generated-form.less │ │ │ ├── key-commands-region.less │ │ │ ├── list-tabular.less │ │ │ ├── menu.less │ │ │ ├── modal.less │ │ │ ├── multiselect-dropdown.less │ │ │ ├── nylas-calendar.less │ │ │ ├── outline-view.less │ │ │ ├── scroll-region.less │ │ │ ├── search-bar.less │ │ │ ├── spinner.less │ │ │ ├── switch.less │ │ │ ├── syncing-list-state.less │ │ │ ├── table.less │ │ │ ├── time-picker.less │ │ │ ├── toast.less │ │ │ ├── tokenizing-text-field.less │ │ │ ├── tutorial-overlay.less │ │ │ ├── undo-toast.less │ │ │ ├── unsafe.less │ │ │ └── webview.less │ │ ├── dropdowns.less │ │ ├── email-frame.less │ │ ├── index.html │ │ ├── index.js │ │ ├── index.less │ │ ├── inputs.less │ │ ├── jasmine.less │ │ ├── linux.less │ │ ├── mixins/ │ │ │ ├── background-variant.less │ │ │ ├── common-ui-elements.less │ │ │ ├── text-emphasis.less │ │ │ └── windows.less │ │ ├── normalize.less │ │ ├── package-template/ │ │ │ ├── README.md │ │ │ ├── lib/ │ │ │ │ ├── main.es6 │ │ │ │ ├── my-composer-button.jsx │ │ │ │ └── my-message-sidebar.jsx │ │ │ ├── spec/ │ │ │ │ ├── main-spec.es6 │ │ │ │ └── my-composer-button-spec.jsx │ │ │ └── stylesheets/ │ │ │ └── main.less │ │ ├── resizable.less │ │ ├── selection.less │ │ ├── sounds/ │ │ │ ├── mail_sent.ogg │ │ │ └── new_mail.ogg │ │ ├── type.less │ │ ├── utilities.less │ │ ├── variables/ │ │ │ ├── ui-mixins.less │ │ │ └── ui-variables.less │ │ └── workspace.less │ ├── client-sync/ │ │ ├── README.md │ │ ├── main.es6 │ │ ├── package.json │ │ ├── spec/ │ │ │ ├── fixtures/ │ │ │ │ ├── FetchFolderList/ │ │ │ │ │ ├── gmail-bengotow.json │ │ │ │ │ └── imap-inboxapptest1.json │ │ │ │ ├── MessageUtils/ │ │ │ │ │ ├── parseFromImap/ │ │ │ │ │ │ ├── crypto-gram-ascii-plaintext.json │ │ │ │ │ │ ├── eff-plaintext-no-mime.json │ │ │ │ │ │ ├── hacker-newsletter-multipart-alternative.json │ │ │ │ │ │ ├── mileageplus-mime-html-only.json │ │ │ │ │ │ ├── node-streamtest-windows-1252.json │ │ │ │ │ │ ├── spam-mime-html-base64-encoded.json │ │ │ │ │ │ └── theskimm-multipart-alternative-quoted-printable.json │ │ │ │ │ └── parseSnippet/ │ │ │ │ │ ├── finimize.html │ │ │ │ │ ├── finimize.txt │ │ │ │ │ ├── fittymi.html │ │ │ │ │ ├── fittymi.txt │ │ │ │ │ ├── mit_events.html │ │ │ │ │ ├── mit_events.txt │ │ │ │ │ ├── personal_capital.html │ │ │ │ │ └── personal_capital.txt │ │ │ │ └── Threading/ │ │ │ │ ├── remote-thread-id-no.js │ │ │ │ ├── remote-thread-id-yes.js │ │ │ │ ├── subject-matching-no.js │ │ │ │ └── subject-matching-yes.js │ │ │ ├── helpers.js │ │ │ ├── local-sync-worker/ │ │ │ │ ├── imap-helpers-spec.es6 │ │ │ │ ├── sync-process-manager-spec.es6 │ │ │ │ ├── sync-tasks/ │ │ │ │ │ └── fetch-folder-list-spec.js │ │ │ │ └── syncback-tasks/ │ │ │ │ └── syncback-task-spec.es6 │ │ │ ├── message-processor/ │ │ │ │ └── detect-thread-spec.js │ │ │ └── shared/ │ │ │ └── interruptible-spec.es6 │ │ ├── src/ │ │ │ ├── local-api/ │ │ │ │ ├── decorators/ │ │ │ │ │ └── connections.js │ │ │ │ ├── default-sync-policy.js │ │ │ │ ├── index.js │ │ │ │ ├── newrelic.js │ │ │ │ ├── route-helpers.es6 │ │ │ │ ├── routes/ │ │ │ │ │ ├── auth.js │ │ │ │ │ ├── calendars.js │ │ │ │ │ ├── categories.js │ │ │ │ │ ├── contacts.js │ │ │ │ │ ├── drafts.js │ │ │ │ │ ├── events.js │ │ │ │ │ ├── files.js │ │ │ │ │ ├── health.es6 │ │ │ │ │ ├── messages.js │ │ │ │ │ ├── ping.js │ │ │ │ │ ├── send.js │ │ │ │ │ └── threads.js │ │ │ │ ├── search.js │ │ │ │ └── serialization.js │ │ │ ├── local-sync-dashboard/ │ │ │ │ ├── dropdown.jsx │ │ │ │ ├── elapsed-time.jsx │ │ │ │ ├── modal.jsx │ │ │ │ ├── root.jsx │ │ │ │ ├── set-all-sync-policies.jsx │ │ │ │ ├── sync-graph.jsx │ │ │ │ └── syncback-request-details.jsx │ │ │ ├── local-sync-worker/ │ │ │ │ ├── imap-helpers.js │ │ │ │ ├── index.js │ │ │ │ ├── local-sync-delta-emitter.es6 │ │ │ │ ├── newrelic.js │ │ │ │ ├── send-task-manager.es6 │ │ │ │ ├── send-task-runner.es6 │ │ │ │ ├── sync-process-manager.es6 │ │ │ │ ├── sync-task-factory.js │ │ │ │ ├── sync-tasks/ │ │ │ │ │ ├── fetch-folder-list.imap.es6 │ │ │ │ │ ├── fetch-messages-in-folder.imap.es6 │ │ │ │ │ ├── fetch-new-messages-in-folder.imap.es6 │ │ │ │ │ ├── fetch-specific-messages-in-folder.imap.es6 │ │ │ │ │ └── sync-task.js │ │ │ │ ├── sync-utils.es6 │ │ │ │ ├── sync-worker.es6 │ │ │ │ ├── syncback-task-factory.js │ │ │ │ ├── syncback-task-runner.es6 │ │ │ │ └── syncback-tasks/ │ │ │ │ ├── create-category.imap.es6 │ │ │ │ ├── delete-folder.imap.es6 │ │ │ │ ├── delete-label.imap.es6 │ │ │ │ ├── ensure-message-in-sent-folder.imap.es6 │ │ │ │ ├── mark-thread-as-read.imap.es6 │ │ │ │ ├── mark-thread-as-unread.imap.es6 │ │ │ │ ├── move-thread-to-folder.imap.es6 │ │ │ │ ├── rename-folder.imap.es6 │ │ │ │ ├── rename-label.imap.es6 │ │ │ │ ├── send-message-per-recipient.smtp.es6 │ │ │ │ ├── send-message.smtp.es6 │ │ │ │ ├── set-thread-folder-and-labels.imap.es6 │ │ │ │ ├── set-thread-labels.imap.es6 │ │ │ │ ├── star-thread.imap.es6 │ │ │ │ ├── sync-unknown-uids.imap.es6 │ │ │ │ ├── syncback-task.es6 │ │ │ │ └── unstar-thread.imap.es6 │ │ │ ├── message-processor/ │ │ │ │ ├── detect-thread.js │ │ │ │ ├── extract-contacts.js │ │ │ │ ├── extract-files.js │ │ │ │ └── index.js │ │ │ ├── models/ │ │ │ │ ├── contact.js │ │ │ │ ├── file.js │ │ │ │ ├── folder.es6 │ │ │ │ ├── label.js │ │ │ │ ├── message.js │ │ │ │ ├── messageLabel.js │ │ │ │ ├── messageReference.js │ │ │ │ ├── reference.js │ │ │ │ ├── syncbackRequest.js │ │ │ │ ├── thread.js │ │ │ │ ├── threadFolder.js │ │ │ │ └── threadLabel.js │ │ │ └── shared/ │ │ │ ├── database-extensions.js │ │ │ ├── dedupe-accounts.es6 │ │ │ ├── imap-paths-utils.js │ │ │ ├── interruptible.js │ │ │ ├── local-database-connector.js │ │ │ ├── logger.es6 │ │ │ ├── shim-sequelize.es6 │ │ │ ├── stream-decoders.es6 │ │ │ ├── sync-activity.es6 │ │ │ └── transaction-connector.js │ │ └── stylesheets/ │ │ └── index.less │ ├── cloud-api/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app.es6 │ │ ├── package.json │ │ ├── spec/ │ │ │ ├── helpers.es6 │ │ │ ├── jasmine/ │ │ │ │ ├── execute.es6 │ │ │ │ ├── extensions.es6 │ │ │ │ └── polyfills.es6 │ │ │ ├── metatdata-spec.es6 │ │ │ └── run.es6 │ │ ├── src/ │ │ │ ├── authentication.es6 │ │ │ ├── decorators/ │ │ │ │ ├── error-format.es6 │ │ │ │ └── logger.es6 │ │ │ ├── routes/ │ │ │ │ ├── admin.es6 │ │ │ │ ├── auth.es6 │ │ │ │ ├── blobs.es6 │ │ │ │ ├── delta.es6 │ │ │ │ ├── honeycomb.es6 │ │ │ │ ├── link-tracking.es6 │ │ │ │ ├── metadata.es6 │ │ │ │ ├── open-tracking.es6 │ │ │ │ ├── ping.es6 │ │ │ │ └── static.es6 │ │ │ ├── sentry.es6 │ │ │ ├── serialization.js │ │ │ ├── tracking-utils.es6 │ │ │ └── views/ │ │ │ ├── admin.html │ │ │ ├── gmail-auth-failure.html │ │ │ ├── gmail-auth-success.html │ │ │ └── layout/ │ │ │ └── default.html │ │ └── static/ │ │ ├── css/ │ │ │ └── index.css │ │ └── fonts/ │ │ └── Avenir.css │ ├── cloud-core/ │ │ ├── README.md │ │ ├── _n1cloud_docker_launcher.sh │ │ ├── build/ │ │ │ └── build-n1-cloud.js │ │ ├── database-connector.es6 │ │ ├── database-extensions.js │ │ ├── gmail-oauth-helpers.es6 │ │ ├── index.js │ │ ├── log-streams.js │ │ ├── logger.js │ │ ├── migrations/ │ │ │ └── 01-expirationDate-metadata.es6 │ │ ├── models/ │ │ │ ├── cloud-job.es6 │ │ │ ├── metadata.js │ │ │ └── pending-auth-response.js │ │ ├── package.json │ │ ├── pm2-debug-cloud-api.yml │ │ ├── pm2-dev.yml │ │ ├── pm2-prod-api.yml │ │ ├── pm2-prod-workers.yml │ │ ├── pubsub-connector.js │ │ ├── scripts/ │ │ │ ├── migrate-db.es6 │ │ │ └── run-redis.sh │ │ └── spec/ │ │ ├── jasmine/ │ │ │ ├── execute.es6 │ │ │ ├── extensions.es6 │ │ │ └── polyfills.es6 │ │ ├── logger-spec.js │ │ └── run.es6 │ ├── cloud-workers/ │ │ ├── README.md │ │ ├── app.es6 │ │ ├── package.json │ │ ├── spec/ │ │ │ ├── jasmine/ │ │ │ │ ├── execute.es6 │ │ │ │ ├── extensions.es6 │ │ │ │ └── polyfills.es6 │ │ │ └── run.es6 │ │ └── src/ │ │ ├── cloud-worker.es6 │ │ ├── foreman.es6 │ │ ├── monitoring.es6 │ │ ├── sentry.es6 │ │ └── workers/ │ │ ├── send-later.es6 │ │ ├── send-reminders.es6 │ │ └── snooze.es6 │ └── isomorphic-core/ │ ├── README.md │ ├── index.js │ ├── package.json │ ├── spec/ │ │ ├── backoff-scheduler-spec.es6 │ │ ├── imap-connection-pool-spec.es6 │ │ ├── jasmine/ │ │ │ ├── config.json │ │ │ ├── execute.es6 │ │ │ ├── extensions.es6 │ │ │ └── polyfills.es6 │ │ ├── message-utils-spec.js │ │ └── run.es6 │ └── src/ │ ├── auth-helpers.es6 │ ├── backoff-schedulers.es6 │ ├── database-types.js │ ├── db-utils.es6 │ ├── delta-stream-builder.js │ ├── env-helpers.es6 │ ├── errors.es6 │ ├── hook-increment-version-on-save.js │ ├── hook-transaction-log.js │ ├── imap-box.es6 │ ├── imap-connection-pool.es6 │ ├── imap-connection.es6 │ ├── imap-errors.es6 │ ├── load-models.js │ ├── message-body-utils.es6 │ ├── message-utils.es6 │ ├── metrics-reporter.es6 │ ├── migrations/ │ │ └── 20160617002207-create-user.js │ ├── model-utils.es6 │ ├── models/ │ │ ├── account-token.js │ │ ├── account.js │ │ └── transaction.js │ ├── promise-utils.js │ ├── sendmail-client.es6 │ ├── shell-utils.es6 │ ├── smtp-errors.es6 │ ├── string-utils.es6 │ ├── tls-utils.es6 │ └── tracking-utils.es6 └── scripts/ ├── benchmark-initial-sync.sh ├── benchmark-new-commits.sh ├── daily.js ├── drop-data-except-accounts.sh ├── postinstall.es6 ├── requirements.txt ├── run-once-per-day.sh └── upload-benchmark-data.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [ "electron", "react" ], "sourceMaps": "inline" } ================================================ FILE: .coffeelint.json ================================================ { "arrow_spacing": { "level": "ignore" }, "camel_case_classes": { "level": "error" }, "coffeescript_error": { "level": "error" }, "colon_assignment_spacing": { "level": "ignore", "spacing": { "left": 0, "right": 0 } }, "cyclomatic_complexity": { "value": 10, "level": "ignore" }, "duplicate_key": { "level": "error" }, "empty_constructor_needs_parens": { "level": "ignore" }, "indentation": { "value": 2, "level": "error" }, "max_line_length": { "value": 140, "level": "error", "limitComments": true }, "missing_fat_arrows": { "level": "ignore" }, "newlines_after_classes": { "value": 3, "level": "ignore" }, "no_backticks": { "level": "error" }, "no_debugger": { "level": "warn" }, "no_empty_functions": { "level": "ignore" }, "no_empty_param_list": { "level": "ignore" }, "no_implicit_braces": { "level": "ignore", "strict": true }, "no_implicit_parens": { "strict": true, "level": "ignore" }, "no_interpolation_in_single_quotes": { "level": "ignore" }, "no_plusplus": { "level": "ignore" }, "no_stand_alone_at": { "level": "ignore" }, "no_tabs": { "level": "error" }, "no_throwing_strings": { "level": "error" }, "no_trailing_semicolons": { "level": "error" }, "no_trailing_whitespace": { "level": "error", "allowed_in_comments": false, "allowed_in_empty_lines": true }, "no_unnecessary_double_quotes": { "level": "ignore" }, "no_unnecessary_fat_arrows": { "level": "warn" }, "non_empty_constructor_needs_parens": { "level": "ignore" }, "prefer_english_operator": { "level": "ignore", "doubleNotLevel": "ignore" }, "space_operators": { "level": "ignore" }, "spacing_after_comma": { "level": "ignore" } } ================================================ FILE: .dockerignore ================================================ .arc* .git* arclib **/node_modules packages/client-* !packages/client-app/.babelrc *.swp *~ .DS_Store **/npm-debug.log **/lerna-debug.log # Vim temp files *.swp *.swo # Elastic Beanstalk Files .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml /packages/client-sync/spec-saved-state.json # Built cloud files n1_cloud_dist ================================================ FILE: .ebextensions/enable_docker_cli_on_ssh.config ================================================ # This lets you log in via `eb ssh` and access the docker daemon. # If we don't add the ec2-user to the docker group, then calls to docker # (like `docker ps`) will fail with `Cannot connect to the Docker daemon` # # See: https://blog.cloudinvaders.com/connect-to-docker-daemon-on-aws-beanstalk-ec2-instance/ commands: 0_add_docker_group_to_ec2_user: command: gpasswd -a ec2-user docker test: groups ec2-user | grep -qv docker ================================================ FILE: .ebignore ================================================ .arc* .git* arclib/ **/node_modules/ packages/client-* !packages/client-app/.babelrc *.swp *~ .DS_Store **/npm-debug.log **/lerna-debug.log # Vim temp files *.swp *.swo # Elastic Beanstalk Files .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml /packages/client-sync/spec-saved-state.json # Built cloud files n1_cloud_dist/ ================================================ FILE: .eslintrc ================================================ { "parser": "babel-eslint", "extends": "airbnb", "globals": { "NylasEnv": false, "$n": false, "waitsForPromise": false, "advanceClock": false, "TEST_ACCOUNT_ID": false, "TEST_ACCOUNT_NAME": false, "TEST_ACCOUNT_EMAIL": false, "TEST_ACCOUNT_ALIAS_EMAIL": false }, "env": { "browser": true, "node": true, "jasmine": true }, "rules": { "arrow-body-style": "off", "arrow-parens": "off", "class-methods-use-this": "off", "prefer-arrow-callback": ["error", {"allowNamedFunctions": true}], "eqeqeq": ["error", "smart"], "id-length": "off", "object-curly-spacing": "off", "max-len": "off", "new-cap": ["error", {"capIsNew": false}], "newline-per-chained-call": "off", "no-bitwise": "off", "no-lonely-if": "off", "no-console": "off", "no-continue": "off", "no-constant-condition": "off", "no-loop-func": "off", "no-plusplus": "off", "no-shadow": "error", "no-underscore-dangle": "off", "object-shorthand": "off", "quotes": "off", "quote-props": ["error", "consistent-as-needed", { "keywords": true }], "no-param-reassign": ["error", { "props": false }], "semi": "off", "no-mixed-operators": "off", "import/extensions": ["error", "never", { "json": "always" }], "import/no-unresolved": ["error", {"ignore": ["nylas-exports", "nylas-component-kit", "electron", "nylas-store", "react-dom/server", "nylas-observables", "windows-shortcuts", "moment-round", "better-sqlite3", "chrono-node", "event-kit", "enzyme", "isomorphic-core"]}], "import/no-extraneous-dependencies": "off", "import/newline-after-import": "off", "import/prefer-default-export": "off", "react/no-multi-comp": "off", "react/no-find-dom-node": "off", "react/no-string-refs": "off", "react/no-unused-prop-types": "off", "react/forbid-prop-types": "off", "jsx-a11y/no-static-element-interactions": "off", "react/prop-types": ["error", {"ignore": ["children"]}], "react/sort-comp": "error", "no-restricted-syntax": [ "error", "ForInStatement", "LabeledStatement", "WithStatement" ], "comma-dangle": ["error", { "arrays": "always-multiline", "objects": "always-multiline", "imports": "always-multiline", "exports": "always-multiline", "functions": "ignore" }], "no-useless-return": "off" }, "settings": { "import/core-modules": [ "nylas-exports", "nylas-component-kit", "electron", "nylas-store", "nylas-observables" ], "import/resolver": {"node": {"extensions": [".es6", ".jsx", ".coffee", ".json", ".cjsx", ".js"]}} } } ================================================ FILE: .gitignore ================================================ ##### Elastic Beanstalk Files .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml ##### Arcanist / Phab **/.arcconfig **/.arclint **/arclib ##### Node modules node_modules !packages/client-app/spec/fixtures/packages/package-with-incompatible-native-module/node_modules **/npm-debug.log* **/lerna-debug.log* ##### Certs for building **/build/resources/certs ##### Misc swap files **/*.swp **/*.swo **/*~ **/*# **/.DS_Store **/Thumbs.db **/#emacs # Built cloud files n1_cloud_dist # Built Nylas Mail client packages/client-app/dist # Tests spec-saved-state.json # Symlinked Jasmine config files **/jasmine/config.json !packages/isomorphic-core/spec/jasmine/config.json # Symlinked isomorphic-core Specs packages/client-app/spec/isomorphic-core # Elastic Beanstalk Files .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml # Sqlite amalgamation for scripts scripts/sqlite # Scripts for calculating statistics scripts/toolbox scripts/venv # Python *.pyc # OAuth client secret for talking to Google Sheets client_secret.json /packages/client-app/internal_packages/client-sync ================================================ FILE: .travis.yml ================================================ # The private Nylas monorepo build script. This will build a full signed # release for the Nylas Mail client sudo: false addons: apt: sources: - ubuntu-toolchain-r-test packages: - build-essential - clang - fakeroot - g++-4.8 - git - libgnome-keyring-dev - xvfb - rpm - libxext-dev - libxtst-dev - libxkbfile-dev branches: only: - master - /ci-.*/ - /stable.*/ matrix: include: - os: linux env: NODE_VERSION=6.9 CC=gcc-4.8 CXX=g++-4.8 DEBUG="electron-packager:*" INSTALL_TARGET=client - os: osx env: NODE_VERSION=6.9 CC=clang CXX=clang++ DEBUG="electron-packager:*" INSTALL_TARGET=client install: - git clone https://github.com/creationix/nvm.git /tmp/.nvm - source /tmp/.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use --delete-prefix $NODE_VERSION script: - npm install && npm run build-client cache: directories: - node_modules - apm/node_modules ================================================ FILE: Dockerfile ================================================ # This Dockerfile builds a production-ready image of K2 to be used across all # services. See the Dockerfile documentation here: # https://docs.docker.com/engine/reference/builder/ # Use the latest Node 6 base docker image # https://github.com/nodejs/docker-node FROM node:6 ENV INSTALL_TARGET=cloud # Copy everything (excluding what's in .dockerignore) into an empty dir COPY . /home WORKDIR /home # This installs global dependencies, then in the postinstall script, runs lerna # bootstrap to install and link cloud-api, cloud-core, and cloud-workers. # We need the --unsafe-perm param to run the postinstall script since Docker # will run everything as sudo RUN npm install --unsafe-perm # This uses babel to compile any es6 to stock js for plain node RUN node packages/cloud-core/build/build-n1-cloud # External services run on port 80. Expose it. EXPOSE 5100 # We use a start-aws command that automatically spawns the correct process # based on environmpackages/cloud-coreent variables (which changes instance to instance) CMD packages/cloud-core/_n1cloud_docker_launcher.sh ${AWS_SERVICE_NAME} ================================================ FILE: ISSUE_TEMPLATE.md ================================================ ##### IMPORTANT: Nylas Mail is no longer maintained Nylas Mail is no longer maintained by Nylas - nobody will read or respond to issues filed here. This issue tracker is being kept online because many existing issues contain valuable tips and information. If you're looking for an alternative to Nylas Mail, check out https://getmailspring.com/. It is based on the Nylas Mail source code, maintained by one of the original developers, and features an entirely re-written sync engine. ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2017 Nylas, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Nylas Mail - the open-source, extensible mail client ![N1 Screenshot](https://github.com/nylas/nylas-mail/raw/master/screenshot/hero_graphic_mac%402x.png) **Nylas Mail was an open-source mail client built on the modern web with [Electron](https://github.com/atom/electron), [React](https://facebook.github.io/react/), and [Flux](https://facebook.github.io/flux/).** It was designed to be easy to extend, and many third-party plugins are available that add functionality to the client. **⚠️ Nylas Mail was initially released and open-sourced in early 2015 and was maintained by Nylas until Spring 2017.** While Nylas no longer supports Nylas Mail, you can download the latest release or build it from source. There are also **[several forks](#forks)** that are being actively developed and maintained. # Getting Started ## Setup your Environment (Mac): 1. Install [Homebrew](http://brew.sh/) 1. Install [NVM](https://github.com/creationix/nvm) & Redis `brew install nvm redis` 1. Install Node 6 via NVM: `nvm install 6` 1. `npm install` ## Setup your Environment (Linux - Debian/Ubuntu): 1. Install Node 6+ via NodeSource (trusted): 1. `curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -` 1. `sudo apt-get install -y nodejs` 1. Install Redis locally `sudo apt-get install -y redis-server redis-tools` benefit of letting us use subdomains. 1. `npm install` ## Running Nylas Mail 1. `npm run client`: Starts the app 1. `npm run test-client`: Run the tests 1. `npm run lint-client`: Lint the source (ESLint + Coffeelint + LESSLint) ### Exploring the Source This repository contains the full source code to the Nylas Mail client and it's backend services. It is divided into the following packages: 1. [**Isomorphic Core**](https://github.com/nylas/nylas-mail/tree/master/packages/isomorphic-core): Shared code across local client and cloud servers 1. [**Client App**](https://github.com/nylas/nylas-mail/tree/master/packages/client-app): The main Electron app for Nylas Mail mirrored to open source repo. 1. [**Client Sync**](https://github.com/nylas/nylas-mail/tree/master/packages/client-sync): The local mailsync engine integreated in Nylas Mail 1. [**Client Private Plugins**](https://github.com/nylas/nylas-mail/tree/master/packages/client-private-plugins): Private Nylas Mail plugins (like SFDC) 1. [**Cloud API**](https://github.com/nylas/nylas-mail/tree/master/packages/cloud-api): The cloud-based auth and metadata APIs for N1 1. [**Cloud Core**](https://github.com/nylas/nylas-mail/tree/master/packages/cloud-core): Shared code used in all remote cloud services 1. [**Cloud Workers**](https://github.com/nylas/nylas-mail/tree/master/packages/cloud-workers): Cloud workers for services like send later See `/packages` for the separate pieces. Each folder in `/packages` is designed to be its own stand-alone repository. They are all bundled here for the ease of source control management. ## Digging Deeper In early 2016, the Nylas Mail team wrote [extensive documentation](https://nylas.github.io/nylas-mail/) for the app that was intended for plugin developers. This documentation lives on GitHub Pages and offers a great overview of the app's architecture and important classes. Here are some good places to get started: - [Application Architecture](https://nylas.github.io/nylas-mail/guides/Architecture.html) - [Debugging Nylas Mail](https://nylas.github.io/nylas-mail/guides/Debugging.html) The team has also given conference talks and published blog posts about the client: - [ReactEurope: How React & Flux Turn Apps Into Extensible Platforms](https://www.youtube.com/watch?v=Uu4Yz2HmCgE) - [ForwardJS: Electron, React & Pixel Perfect Experiences](https://www.youtube.com/watch?v=jRPUB-D1Wx0&list=PL7i8CwZBnlf7iUTn2JMVLLWofAhaiK7l3) - [Blog: Splitting from Atom](https://github.com/nylas/nylas-mail/raw/master/blog-posts/splitting-from-atom.pdf) - [Blog: Building Plugins for React Apps](https://github.com/nylas/nylas-mail/raw/master/blog-posts/plugins.pdf) - [Blog: Nylas Mail Build Process](https://github.com/nylas/nylas-mail/raw/master/blog-posts/build-process.pdf) - [Blog: Low level Electron Debugging](https://github.com/nylas/nylas-mail/raw/master/blog-posts/electron-debugging.pdf) - [Blog: A New Search Parser](https://github.com/nylas/nylas-mail/raw/master/blog-posts/search-parser.pdf) - [Blog: Developers Guide to Emoji](https://github.com/nylas/nylas-mail/raw/master/blog-posts/emoji.pdf) - [Blog: Nylas Pro](https://github.com/nylas/nylas-mail/raw/master/blog-posts/nylas-pro.pdf) - [Blog: Nylas Mail & PGP](https://github.com/nylas/nylas-mail/raw/master/blog-posts/pgp.pdf) - [Blog: Calendar Events and RRULEs](https://github.com/nylas/nylas-mail/raw/master/blog-posts/rrules.pdf) ## Running the Cloud When you download and build Nylas Mail from source it runs without its cloud components. The concept of a "Nylas ID" / subscription has been removed, and plugins that require server-side processing are disabled by default. (Plugins like Snooze, Send Later, etc.) In order to use these plugins and get the full Nylas Mail experience, you need to deploy the backend infrastructure located in the `cloud-*` packages. Deploying these services is challenging because they are implemented as microservices and designed to be run at enterprise scale with Redis, Postgres, etc. Because these backend services must access your email account, it is also important to use security best-practices (at the very least, SSL, encryption at rest, and a partitioned VPC). For more information about building and deploying this part of the stack, check out the [cloud-core README](https://github.com/nylas/nylas-mail/blob/master/packages/cloud-core/README.md). ## Themes The Nylas Mail user interface is styled using CSS, which means it's easy to modify and extend. Nylas Mail comes stock with a few beautiful themes, and there are many more which have been built by community developers ![N1 Themes](https://github.com/nylas/nylas-mail/raw/master/screenshot/687474703a2f2f692e696d6775722e636f6d2f505751374e6c592e6a7067.jpg) #### Bundled Themes - [Dark](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/ui-dark) - [Darkside](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/ui-darkside) (designed by [Jamie Wilson](https://github.com/jamiewilson)) - [Taiga](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/ui-taiga) (designed by [Noah Buscher](https://github.com/noahbuscher)) - [Ubuntu](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/ui-ubuntu) (designed by [Ahmed Elhanafy](https://github.com/ahmedlhanafy)) - [Less Is More](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/ui-less-is-more) (designed by [Alexander Adkins](https://github.com/P0WW0W)) #### Community Themes | | | | | ----- | ----- | ----- | | [ToogaBooga](https://github.com/brycedorn/N1-ToogaBooga) | [Material](https://github.com/jackiehluo/n1-material) | [Monokai](https://github.com/dcondrey/n1-monokai) | | [Agapanthus](https://github.com/taniadaniela/n1-agapanthus)—Inbox-inspired theme | [Stripe](https://github.com/oeaeee/n1-stripe)| [Kleinstein](https://github.com/diklein/Kleinstein)—Hides account sidebar| | [Arc Dark](https://github.com/varlesh/Nylas-Arc-Dark-Theme)| [Solarized Dark](https://github.com/NSHenry/N1-Solarized-Dark) | [Darkish](https://github.com/dyrnade/N1-Darkish)| | [Predawn](https://github.com/adambmedia/N1-Predawn)| [Ido](https://github.com/edipox/n1-ido)—Polymail-inspired theme|[Berend](https://github.com/Frique/N1-Berend) | | [ElementaryOS](https://github.com/edipox/elementary-nylas) | [LevelUp](https://github.com/stolinski/level-up-nylas-n1-theme)|[Sunrise](https://github.com/jackiehluo/n1-sunrise) | | [BoraBora](https://github.com/arimai/N1-BoraBora) | [Honeyduke](https://github.com/arimai/n1-honeyduke)| [Snow](https://github.com/Wattenberger/N1-snow-theme)| |[Hull](https://github.com/unity/n1-hull)|[Express](https://github.com/oeaeee/n1-express)|[DarkSoda](https://github.com/adambullmer/N1-theme-DarkSoda)| |[Bemind](https://github.com/bemindinteractive/Bemind-N1-Theme)|[Dracula](https://github.com/dracula/nylas-n1)|[MouseEatsCat](https://github.com/MouseEatsCat/MouseEatsCat-N1)| |[Sublime Dark](https://github.com/rishabhkesarwani/Nylas-Sublime-Dark-Theme)|[Firefox](https://github.com/darshandsoni/n1-firefox-theme)|[Gmail](https://github.com/dregitsky/n1-gmail-theme)| #### To install community themes: 1. Download and unzip the repo 2. In Nylas Mail, select `Developer > Install a Package Manually... ` 3. Navigate to where you downloaded the theme and select the root folder. The theme is copied into the `~/.nylas-mail` folder for your convinence 5. Select `Change Theme...` from the top level menu, and you'll see the newly installed theme. That's it! Want to dive in more? Try [creating your own theme](https://github.com/nylas/nylas-mail-theme-starter)! ## Plugins Some plugins come pre-installed, and are a great starting points for creating your own: - [Translate](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/composer-translate)—Works with 10 languages - [Quick Replies](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/composer-templates)—Send emails faster with templates - [Emoji Keyboard](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/composer-emoji)—Insert emoji by typing a colon (:) followed by the name of an emoji symbol - [GitHub Sidebar Info](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/github-contact-card) - [View on GitHub](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/message-view-on-github) - [Personal Level Indicators](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/personal-level-indicators) - [Phishing Detection](https://github.com/nylas/nylas-mail/tree/master/packages/client-app/internal_packages/phishing-detection) #### Community Plugins Note these are not tested or officially supported by Nylas, but we still think they are really cool! If you find bugs with them, please open GitHub issues on their individual project pages, not the Nylas Mail (N1) repo page. Thanks! | | | | | ----- | ----- | ----- | |[Jiffy](http://noahbuscher.github.io/N1-Jiffy/)—Insert animated GIFs|[Weather](https://github.com/jackiehluo/n1-weather)|[Todoist](https://github.com/alexfruehwirth/N1TodoistIntegration)| |[Unsubscribe](https://github.com/colinking/n1-unsubscribe)|[Squirt Speed Reader](https://github.com/HarleyKwyn/squirt-reader-N1-plugin/)|[Website Launcher](https://github.com/adriangrantdotorg/nylas-n1-background-webpage)—Opens a URL in separate window| |[Cypher](https://github.com/mbilker/cypher)—PGP Encryption|[Avatars](https://github.com/unity/n1-avatars)|[Events Calendar (WIP)](https://github.com/nerdenough/n1-events-calendar)| |[Mail in Chat (WIP)](https://github.com/yjchen/mail_in_chat)|[Evernote](https://github.com/grobgl/n1-evernote)|[Wunderlist](https://github.com/miguelrs/n1-wunderlist)| |[Participants Display](https://github.com/kbruccoleri/nylas-participants-display)|[GitHub](https://github.com/ForbesLindesay/N1-GitHub)|| When you install packages, they're moved to ~/.nylas-mail/packages, and Nylas Mail runs apm install on the command line to fetch dependencies listed in the package's package.json # Forks There are several forks of Nylas Mail that you should check out. If you're just learning about Nylas Mail, it is highly recommended you use one of these instead. - [Mailspring](http://www.getmailspring.com/) - Significant rewrite by one of the original authors focused on performance and cloud plugins - [Nylas Mail Lives](https://github.com/nylas-mail-lives/nylas-mail) - Community effort to fix bugs and improve the client! (Seeking Maintainers) ================================================ FILE: appveyor.yml ================================================ version: '{build}' branches: only: - master - /ci.*/ - /stable.*/ # We need to only clone the main module because our submodule requires the # encrypted ssh key to access submodules install: - ps: Install-Product node $env:NODE_VERSION - ps: nuget install secure-file -ExcludeVersion - ps: npm config set msvs_version 2013 build_script: - cmd: npm install deploy_script: - ps: | npm run build-client environment: matrix: - NODE_VERSION: 6.9 global: DEBUG: "electron-windows-installer:*,electron-packager:*" SIGN_BUILD: true INSTALL_TARGET: "client" CERTIFICATE_FILE: .\packages\client-private-plugins\encrypted_certificates\appveyor\win-nylas-n1.p12 DECRYPTION_PASSWORD: secure: 48VSzDtdBd52Xlo3TZ1NeR1yRRrZ3AU6Px5XjD5RDp44cFU5GYVspecGqX6DGCV7i0D7nldGMyEbXNrjM1t1Kw== cache: - node_modules -> package.json - packages\client-app\node_modules -> packages\client-app\package.json - '%USERPROFILE%\.npm' ================================================ FILE: lerna.json ================================================ { "lerna": "2.0.0-beta.38", "version": "0.0.1" } ================================================ FILE: package.json ================================================ { "name": "nylas-mail-all", "version": "0.0.1", "description": "All components required to run Nylas Mail", "devDependencies": { "babel-cli": "6.x.x", "babel-core": "6.x.x", "babel-eslint": "7.1.0", "babel-preset-electron": "1.4.15", "babel-preset-react": "6.x.x", "chalk": "1.x.x", "coffeelint-cjsx": "2.x.x", "commander": "^2.9.0", "electron-installer-dmg": "0.2.x", "electron-packager": "8.4.x", "electron-winstaller": "2.x.x", "eslint": "3.10.1", "eslint-config-airbnb": "13.0.0", "eslint-plugin-import": "2.2.0", "eslint-plugin-jsx-a11y": "2.2.3", "eslint-plugin-react": "6.7.1", "eslint_d": "4.2.0", "fs-extra": "2.x.x", "fs-plus": "2.x.x", "glob": "7.x.x", "grunt": "0.4.x", "grunt-cli": "0.1.x", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-coffeelint-cjsx": "0.1.x", "grunt-contrib-coffee": "0.12.x", "grunt-contrib-csslint": "0.5.x", "grunt-contrib-less": "0.8.x", "grunt-lesslint": "0.13.x", "jasmine": "2.x.x", "lerna": "emorikawa/lerna#v2.0.0-beta.38.forked", "load-grunt-parent-tasks": "0.1.1", "mkdirp": "^0.5.1", "pm2": "2.4.0", "request": "2.x.x", "s3": "4.x.x", "temp": "0.8.x", "underscore": "1.8.x" }, "scripts": { "start": "npm run client", "test": "npm run test-client && npm run test-cloud", "client": "packages/client-app/node_modules/.bin/electron packages/client-app --enable-logging --dev", "benchmark": "packages/client-app/node_modules/.bin/electron packages/client-app --enable-logging --dev --benchmark", "test-client": "packages/client-app/node_modules/.bin/electron packages/client-app --enable-logging --test", "test-client-window": "packages/client-app/node_modules/.bin/electron packages/client-app --enable-logging --test=window", "test-client-junit": "", "lint-client": "grunt lint --gruntfile=packages/client-app/build/Gruntfile.js --base=./", "build-client": "grunt build-client --gruntfile=packages/client-app/build/Gruntfile.js --base=./", "cloud": "pm2 stop all; pm2 delete all; pm2 start packages/cloud-core/pm2-dev.yml --no-daemon", "cloud-debug": "pm2 stop all; pm2 delete all; pm2 start packages/cloud-core/pm2-debug-cloud-api.yml --no-daemon", "test-cloud": "cd packages/cloud-api && npm test && cd ../cloud-core && npm test && cd ../cloud-workers && npm test && cd ../isomorphic-core && npm test", "stop": "npm run stop-cloud", "stop-cloud": "pm2 stop all; pm2 delete all;", "build-cloud": "docker build .", "postinstall": "babel-node scripts/postinstall.es6", "daily": "babel-node scripts/daily.js" }, "repository": { "type": "git", "url": "git+https://github.com/nylas/nylas-mail-all.git" }, "author": "Nylas", "license": "proprietary", "engines": { "node": "6.9.1", "npm": "3.10.8" } } ================================================ FILE: packages/README.md ================================================ # Monorepo Packages Each folder here is designed to act as its own repository. For development convenience, they are all included here in one monorepo. This allows us to grep across multiple codebases, not use submodules, and keep a unified commit history. We use [Lerna](https://github.com/lerna/lerna) to manage the monorepo and tie them all together with the main `nylas-mail-all/scripts/postinstall.es6` script, which in turn, calls `lerna bootstrap` ================================================ FILE: packages/client-app/.babelrc ================================================ { "presets": [ "electron", "react" ], "sourceMaps": "inline" } ================================================ FILE: packages/client-app/.travis.yml ================================================ # The open source Nylas Mail Client for Linux and Mac. See AppVeyor for # Windows sudo: false addons: apt: sources: - ubuntu-toolchain-r-test packages: - build-essential - clang - fakeroot - g++-4.8 - git - libgnome-keyring-dev - xvfb - rpm - libxext-dev - libxtst-dev - libxkbfile-dev branches: only: - master - /ci-.*/ - /stable.*/ matrix: include: - os: linux env: NODE_VERSION=6.9 CC=gcc-4.8 CXX=g++-4.8 - os: osx env: NODE_VERSION=6.9 CC=clang CXX=clang++ install: - git clone https://github.com/creationix/nvm.git /tmp/.nvm - source /tmp/.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use --delete-prefix $NODE_VERSION before_script: - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start; fi script: - npm install && npm test cache: directories: - node_modules - apm/node_modules ================================================ FILE: packages/client-app/.watchmanconfig ================================================ { "ignore_dirs": [ "build/node_modules", "apm/node_modules", "node_modules", "src/K2/node_modules", "src/K2/packages/local-sync/node_modules", "src/K2/packages/isomorphic-core/node_modules", "src/K2/packages/cloud-api/node_modules", "src/K2/packages/cloud-workers/node_modules", "src/K2/packages/cloud-core/node_modules" ] } ================================================ FILE: packages/client-app/CHANGELOG.md ================================================ # Nylas Mail Changelog ### 2.0.32 (5/1/2017) + Remove unnecessary tracking events ### 2.0.31 (4/28/2017) - Fixes: + Fix invalid credentials error when sending on Gmail. This error will happen sporadically, and was introduced in version 2.0.28 ### 2.0.28 (4/26/2017) - Fixes: + Fix send later with open/link tracking ### 2.0.27 (4/26/2017) - Fixes: + Don't throw error when search query has trailing whitespace ### 2.0.26 (4/26/2017) - Fixes: + Fix self-triggering in open and link tracking + Speed up sending per recipient + Fix open and link tracking when sending per recipient - Development: + Consolidate TrackingUtils & better documentation ### 2.0.23 (4/25/2017) - Fixes: + Properly retry retryable errors in syncback tasks ### 2.0.21 (4/24/2017) - Fixes: + Fix throwing errors inside Interruptible + Fix sending on Gmail with large attachments (caused by conflict with syncing sent folder) + Increment max size for attachments ### 2.0.20 (4/24/2017) - Fixes: + Correctly pass connSettings to convertSmtpError + Fix attachment previews + Fix link editor jumping away from you in composer + Fix certificate error msg + Detect smtp cert errors and relax condition to detect them ### 2.0.19 (4/21/2017) - Features: + Allow users to select custom folder mappings for Sent and Trash folders + Move messages out of db into compressed flat files for better space efficiency - Performance: + 10x speed improvement for sending messages + Improve performance of all syncback tasks by 500ms - Fixes: + Correctly cleanup orphaned messages during sync - Development: + Refactor sending code and remove cruft + Fix the specs ### 2.0.18 (4/21/2017) - Fixes: + Correctly track all auth errors & correlate to email + Add more IMAP provider settings from Mozilla's ISPDB + Allow bypassing of invalid certificates during authentication + Don't double report auth errors ### 2.0.17 (4/19/2017) - Fixes: + Record auth error location to Mixpanel + Show proper auth error messages to users + Correctly identify more certificate errors + Fix offline notification behind proxies + Fix attachment filename encodings - Development + Prevent from running daily when untracked files present in working dir + Fixup auth helpers ### 2.0.16 (4/18/2017) - Fixes: + Better handling of startup errors + Fix occasional EPERM issues on boot on Windows + Reduce CPU limits for historical sync + Fix search parser to handle nested queries properly + Update copy that still referenced N1 to Nylas Mail - Development: + Fix benchmark mode ### 2.0.15 (4/17/2017) + Correctly handle and inform users about database malformed errors that can occur both in main process and/or window processes ### 2.0.14 (4/14/2017) - Fixes: + Prevent from adding duplicate accounts and sync workers due to account id changes + Correctly remove sync worker reference when destroying it + Correctly initialize SyncProcessManager with Identity + Fix contact ranking runtime error ### 2.0.13 (4/13/2017) - Fixes: + Upload nupkg with correct name for win32 autoupdater to work + Correctly handle window.unhandledrejection events ### 2.0.12 (4/13/2017) - Fixes: + Prevent NM from overwriting N1 binary on windows + Fix runtime error in sync process + Prevent old N1 config from getting wiped when installing Nylas Mail - Development: + Remove useless docs ### 2.0.11 (4/12/2017) - Fixes: + Dispose of mail listener connection before getting new one. This will prevent sync process from leaking Imap connections and getting stuck. + Fix performance regression when polling for gmail attribute changes + Don't double report unhandled rejections + Fix unhandled rejection handling (fix ipc parse error) + Fix regression when processing messages under a transaction + Rate limit database malformed error reports to sentry ### 2.0.10 (4/11/2017) - Fixes: + Fix missing UID error when archiving threads after sending + Ensure all mail folder exists before trying to access it + Fix SyncbackMetadataTask dependency - Development: + Don't report stuck sync processes to Sentry + MessageFactory -> MessageUtils, SendUtils -> ModelUtils ### 2.0.9 (4/11/2017) - Features: + Re-add imap to the onboarding accounts page - Fixes: + Correctly detect changes in labels, starred and unread for Gmail accounts + Fix delta streaming connection retries + Handle weird MIME edge case with @ symbol - Performance: + Wrap message processing in transaction for better performance + Increase sqlite `page_size` and `cache_size` - Cloud: + Improve performance of reminders worker + Add DataDog StatsD for heartbeats + Restart automatically on unhandeld rejections - Development: + Add benchmark mode ### 2.0.8 (4/7/2017) - Fixes: + Revamp SSL options during authentication to be able to properly auth against SMTP and prevent sending failures + Ensure IMAPConnnectionPool uses updated account credentials + Always fetch and update identity regardless of environment + Properly handle serialization errors for JSON columns in database - Cloud: + Switch MySQL charset to utf8mb4 + Add exponential backoff for cloud worker jobs when encountering errors + Use IMAP connection pool in cloud workers to limit number of connections + Properly generate metadata deltas when clearing expiration field + Increment default imap connection socket timeout in cloud workers - Plugins: + Correctly syncback metadata for send later + Delete drafts after they are sent later + Correctly ensure messages in sent folder for send later in gmail + Fix send reminders version conflict error + Correctly set metadata values for send reminders + Fix imap folder names in send-reminders + Fix send later access token refresh - Development: + Add view of CloudJobs in n1.nylas.com/admin + Ensure daily script grabs current version after pulling latest changes ### 2.0.1 (4/5/2017) - Features: + Limit search to focused perspective - Fixes: + IMAPConnectionPool now correctly disposes connections + Ensure we use refreshed access token for all imap connections during sync + Prevent IMAP connection leaking in sync worker + Fix send later button saving state and sending action + Fix inline images for send later + Correctly enable plugins on 2.0.1 + Make sure app can update even after signing out of NylasID + Don't make any requests when NylasID isn't present - Cloud: + Make cloud workers more robust + Remove old SignalFX reporter & add docs + Log errors according to bunyan specs - Development: + Add script to run benchmarks once per day at specified time + Add script to upload benchmark data to Google Sheets + Add better logging when restarting stuck sync worker ### 2.0.0 (4/4/2017) Introducing Nylas Mail Pro - Features: + Enable snooze, send later, and send reminders + Add feature limits to reminders and send later - Fixes + Don't assign duplicate folder roles + Re-setup IdentityStore in new window - Development: + Fix sqlite build for older versions of clang + Remove rogue scripts-tmp folder + Remove unecessary db setup for mail rules ### 1.0.55 (3/31/2017) - Fixes + Ensure open/link tracking work when sending multiple consecutive emails + Fix performance of contact rankings database query + Fix performance of thread search index database queries + Fix performance of ANALYZE queries ### 1.0.54 (3/31/2017) - Features: + Add search support for `has:attachment` - Fixes: + Reduce database thrashing caused by thread search indexing + Interrupt long-running syncback tasks + Fix performance of contact rankings db query + Don't hit contact rankings endpoint until account is ready + Ensure sync worker is stopped correctly when removing accounts or when restarting it - Metrics: + Report metrics about SyncbackTask runs - Perf: + Delay building new hot window to improve win perf - Development: + Add script to benchmarks new commits + Add DEBUG flag to be able to log all query activity for both databases + Add `DatabaseStore.write` which doesn't use Transactions + Metadata test fixes ### 1.0.52 (3/29/2017) - Fixes: + Fix open and link tracking: + No longer triggers your own opens & link clicks + Link tracking indicator is now always present in sent messages + Fix regression in DB query execution which would delay all queries in the system. + Reduce max retry backoff for DB queries, which could hold a query open for too long + Fix thread reindexing issues, which should help performance and correctly index threads for search + Fix `in:` search syntax for non-gmail search + Fix references to RetryableError imports - Development: + Add initial sync benchmarking script + Clean up logging in DatabaseStore: differentiate background queries from regular queries in the logs, only log queries that actually take more than 100ms. + Point the billing server URL to staging by default for easier development, and allow it to be overriden + Add index to expiration field on Metadata ### 1.0.51 (3/28/2017) - Features: + Restore contact rankings feature for better contact predictions in composer recipient fields - Fixes: + Correctly listen for new mail in between sync loops + Verify SMTP credentials in /auth endpoint + Also prioritize sent label for initial Gmail sync + Properly relaunch windows on autoupdate + Properly set up local /health endpoint by making sure to attach route files ending in .es6 to local-api - Perf: + Don't throttle while syncing first 500 threads - Metrics: + Report battery state changes to Mixpanel - Development: + Make deploy-it say what it's doing instead of hanging silently + Make deploy-it print link to the EB console + Make help message better on deploy-it + Add `SHOW_HOT_WINDOW` env for prod debugging of window launches + Correctly ignore `node_modules` in .ebignore for faster deploys + Only bootstrap specific pkgs in postinstall for faster npm installs ### 1.0.50 (3/28/2017) - Fixes: + Fix SyncActivity errors introduced in 1.0.49 ### 1.0.49 (3/27/2017) - Fixes: + Ensure sync process does not get stuck + Ensure the worker window is always available + Retry database operations when encountering locking issues - Metrics: + Detect and report when the worker window is unavailable + Detect and report when a sync process is stuck - Development: + Windows autoupdater fixes + Add better documentation for windows autoupdater + Remap windows dev shortcuts to match the ones used on darwin and linux + When building app, only re-install for optional dependencies on darwin - Cloud: + Timeout streaming API connections every 15 minutes + Add missing database indexes from SQL review ### 1.0.48 (3/27/2017) - Fixes: + Reindex threads when they're updated + Don't try to restart sync on every IdentityStore change + Correctly remove inline images with x button ### 1.0.47 (3/23/2017) - Fixes: + Report hard crashes using Electron's built-in crash reporter - Development: + Don't handle IMAP timeouts in the connection pool + Record file download times ### 1.0.46 (3/22/2017) - Fixes: + Ensure files get transferred in forwarded messages + Correctly sign out of NylasID + Don't report non-reportable errors in delta connection + Fix S3 attachment upload for send later - Development: + Rename downloadDataForFile(s) -> getDownloadDataForFile(s) + Switch type of Metadata value column + Fix build condition + Fix DraftFactory specs + Refactor sync worker IMAPConnectionPool callbacks ### 1.0.45 (3/21/2017) - Fixes: + Correctly report unhandled errors caught in window. + Fix passing cursor to delta streams ### 1.0.44 (3/20/2017) - Fixes: + Add error handling when creating syncback requests + Fix path for tmp dir in daily script ### 1.0.43 (3/17/2017) - Fixes: + Revert nodemailer to previous version + Creating a folder no longer creates a non-existent duplicate subfolder + Don't bump threads to the top of list when a message is sent: only update lastReceivedDate if the message was actually received ### 1.0.42 (3/16/2017) - Fixes: + Fix spellchecker regression (Don't exclude source maps in build) ### 1.0.41 (3/16/2017) - Development: + Upgrade nodemailer to latest version ### 1.0.40 (3/15/2017) - Features: + Add support for attachments in send later - Development: + Improve build time + Windows Autoupdater fixes ### 1.0.39 (3/14/2017) - Fixes: + Fix missing depedency for imap-provider-settings - Development: + Only upload 7 characters of the commit hash for Windows build ### 1.0.38 (3/13/2017) - Fixes: + Restart sync when computer awakes from sleep + Fix issue that made users log out of NylasID, restart, and then force them to log out and restart again in a loop (#3325) + Don't start sync or delta connections without an identity - Development: + Restore windows build + Remove specs from production build + Fix arc lint + Specify Content-Type in developer bar curl commands ### 1.0.37 (3/10/2017) - Fixes: + Fix regression introduced in 1.0.36 in the message processor + Correctly show auth error when we can't connect to n1cloud + Fix error thrown sometimes when handling send errors ### 1.0.36 (3/10/2017) - Fixes: + Increase the IMAP connection pool size + Shim sequelize to timeout after 1 minute on every database operation. This is a safeguard to prevent unresolved db promises from halting the sync loop. + Better error handling to prevent the message processor from halting sync - Development: + Measure and report inline composer open times + Refactor MessageProcessor to be more robust to errors ### 1.0.35 (3/9/2017) - Fixes: + Make sure delta connection is restarted when an account is re-authed + More defensive error handling to prevent sync from halting + Prevent delta streaming connection from retrying too much + Fix error when attempting to report a fetch id error + Prevent error restart loop when database is malformed + Correctly cancel search when the search perspective is cleared + When many search results are returned from the server, don't try to sync them all at once, otherwise would slow down the main sync process. + When restarting the app, don't try to continue syncing search results from an old search - Development: + Consolidate delta connection stores, remove `internal_package/deltas` + Rename NylasSyncStatusStore to FolderSyncProgressStore + Consolidate APIError status code that we should not report + Don't report incorrect username or password to Sentry + Rate limit error reporting for message processing errors + Fix circular reference error when reporting errors + Refactor file download IMAPConnectionPool usage + Don't focus the Console tab in dev tools every time an error is logged + Correctly set process title ### 1.0.34 (3/8/2017) - Fixes: + Sync should not get stuck anymore due to sequelize + Delta Streaming connections now correctly retry after they are closed or an error occurs + Handle errors when opening imap box correctly - Development: + Add script/daily + Provide better info to Sentry on sending errors + Refactor and clean up delta streaming code + Refactor message processing throttling ### 1.0.33 (3/8/2017) - Features: + Add intitial support for send later - Fixes: + Fetch unknown message uids returned in search results + Don't throttle message processing when syncing specific UIDs - Development: + Better grouping for APIError by URL also + Don't generate sourceMapCache in prod mode + Upload a next-version to S3 for autoupdate testing + Windows build fixes ### 1.0.32 (3/7/2017) - Development: + Report provider when reporting remove-from-threads-from-list + Report provider when reporting send perf metrics ### 1.0.31 (3/6/2017) - Fixes: + Improve initial sync speed by scaling number of messages synced based on folder SELECT duration + Immediately restore sync process when app comes back online after being disconnected from the internet. + Can now reply from within notifications again - Development: + Add basic rate limiting to Sentry + Report all search performance metrics + Prevent noisy uncaught errors when closing long connection + Improve reporting of refresh access token errors + Don't double report refresh access token API errors + Replace `setImmediate` with `setTimeout` as Promise scheduler + Use new Bluebird preferred `longStackTraces` syntax + NylasAPIRequest refactored and cleaned up + Search refactors and improvements + Protect from operating on IMAP connection while opening a box + Enable logging in prod builds + Make deploy-it support -h/--help + Restore cloud testing environments ### 1.0.30 (2/28/2017) - Fixes: + Can properly add signatures and select them as default for different accounts. + Can now correctly reply to a thread and immediately archive it or move it to another folder without throwing an error (#3290) + Correctly fix IMAP connection timeout issues (#3232) + Nylas Mail no longer opens an increasing number of IMAP connections which caused some users to reach IMAP server connection limits (#3228) + Fix memory leak while syncing which caused sync process to restart sometimes. + Correctly handle IMAP connections ending unexpectedly + Correctly detect retryable IMAP errors during sync + detect more retryable errors + Correctly catch more authentication errors when sending + Improve speed of processing messages during sync + Prevent unnecessary re-renders of the thread list - Development: + Report performance metrics + More Coffeescript to Javascript conversions ### 1.0.29 (2/21/2017) - Fixes: + You can now click inline images in messages to open them + More IMAP errors have been identified as retryable, which means users will see less errors when syncing an account + Improve performance of thread search indexing queries + Correctly catch Invalid Login errors when sending - Development: + Developer bar in Worker window now shows single delta connection + More code converted to Javascript ### 1.0.28 (2/16/2017) - Fixes: + Fix offline notification bug that caused api outage + We now properly handle gmail auth token errors in the middle of the sync loop. This means less red boxes for users! + Less battery usage when initial sync has completed! + No more errors when saving sent messages to sent folders (`auth or accountId` errors) + No more `Lingering tasks in progress marked as failed errors` + Syncback tasks will continue retrying even after closing app + Syncback tasks retry more aggressively + Detect more offline errors when sending, sending is more reliable + Imap connection pooling (yet to land) + More retryable IMAP errors, means less red boxes for users + Offline notification now shows itself when we’re actually offline, shows countdown for next reconnect attempt - Development: + More tests + Don't use breadcrumbs in dev mode + Add a better reason when waking sync for syncback in the logs + BackoffScheduler, BatteryManager added for reusability ### 1.0.27 (2/14/17) - Fixes: + Offline notification fixes ### 1.0.26 (2/10/17) - Fixes: + Downloads retry if they fail + NylasID doesn't intermittently log out or throw errors + Fix initial sync for Inbox Zero Gmail accounts ### 1.0.25 (2/10/17) - Fixes: + When replying to a thread, properly add it to the sent folder - Development: + Can now once again run Nylas Mail test suite ### 1.0.24 (2/9/17) - Fixes: + Fix error reporter when reporting an error without an identity (this would crash the app) - Development: + Fix logging inside local-sync api requests + Stop reporting handled API errors to Sentry + Report thread-list perf metrics ### 1.0.23 (2/8/17) - Fixes: + Fix emails occasionally being sent with an incomplete body (#3269) + Correctly thread messages together when open/link tracking is enabled + Fix `Mailbox does not exist` error for iCloud users (#3253) + When adding account, correctly remove whitespace from emails + Fix link in update notification to point to latest changelog - Performance: + Thread list actions no longer sporadically lag for ~1sec (this is especially noticeable when many accounts have been added) + No longer slow down sync process when more than 100,000 threads have been synced - Development: + Better logging in worker window + You can now run a development build of Nylas Mail alongside a production build ### 1.0.22 (2/7/17) - Fixes: + New mail notification sounds on startup are combined when multiple new messages have arrived + You can now correctly select threads using `cmd` and `shift` + Improve message fetching by making sure we always fetch the most recent messages first. + Improve IMAP connection timeouts by incrementing the socket timeout (#3232) + When adding a Google account, make sure to show the Account Chooser - Development: + Nylas Identity is no longer stored in config.json ### 1.0.21 (2/3/17) - Fixes: + Fixed an issue where Nylas Mail could delete all accounts (addresses #3231) + Correctly delete and archive threads when they contain sent messages (addresses #2706) + Improve performance and prevent crashes when running several sync actions + Improve error handling when sync actions fail + Fix JSON serialization issue which could cause sync process to error. ### 1.0.20 (2/1/17) - Fixes: + Properly clean up broken replies ### 1.0.19 (1/31/17) - Fixes: + Replies on threads won't create duplicate-looking emails. This began to happen on midnight February 1 UTC due to a date parsing bug + Improve error handling in sync + Better retrying of certain syncback actions - Development: + Now using Electron 1.4.15 ### 1.0.18 (1/30/17) - Performance: + 60% reduction of CPU usage during initial sync due to optimizing unnecessary rendering - Fixes: + New composer stays in "to" field when initially typing - Development: + Better documentation for Nylas Mail SDKs + GitHub repository renamed from nylas/N1 to nylas/nylas-mail + `master` branch now has Nylas Mail (1.0.x) + `n1-pro` branch now has Nylas Pro (1.5.x) ### 1.0.17 (1/27/17) - Fixes: + Fix send and archive: Can now archive after sending without errors + Local search now includes more thread results + Contact autocomplete in composer participant fields now includes more results ### 1.0.16 (1/27/17) - Performance: + Improved typing performance in the composer, especially with misspelled words - Fixes: + Nylas Mail plugins install properly + Fix undo and occasional archive & move tasks failing due to not having uids + Fix logging for auth + Properly clean up after file downloads + Properly recover from IMAP uid invalidity ### 1.0.15 (1/25/17) - Features: + Improve CPU performance of idle windows - Fixes: + Correctly detect initial battery status for throttling. + Correctly allow auth for Custom IMAP accounts only #3185 ### 1.0.14 (1/25/17) - Features: + Improved spellchecker - Fixes: + Correctly update attributes like starred and unread when syncing folders. Marking as read or starred will no longer bounce back. + Correctly detect new mail while syncing Gmail inbox. ### 1.0.13 (1/25/17) - Fixes: + Messages immediately appear in sent folder. No bouncing back. + Login more likely to succeed. Waits longer for IMAP + Doesn't allow invalid form submission + Correctly handles token refresh failing + Auto updater says "Nylas Mail" properly + Sync drafts correctly on Gmail - Development: + Local sync account API deprecated + Silence noisy queries in the logs ### 1.0.12 (1/24/17) - Features: + New 'Debug' sync button that opens up the console + Faster search + Message processing now throttles when on battery + Analytics for change mail tasks - Fixes: + Archive, Mark as Unread, and Move to trash don't "bounce back" + Adding a new account is now smoother + Improved threading + Drafts are no longer in the inbox ### 1.0.11 (1/19/17) - Features: + Nylas Mail's installer on Mac uses a DMG - Fixes: + Fixed app being occasionally unresponsive + Decreased odds of failed logins (by bumping connection timeout value) + Sync erroring notification no longer tripped by timeouts ### 1.0.10 (1/19/17) - Features: + "Contact Support" button now auto-fills information + Actions reach providers faster - Fixes: + Show errors on the GMail auth screen + Show draft sending errors + Can now correctly search threads via `from:` and `to:` + Other error management improvements + The database will now be reset if malformed + Improve the offline notification - Development: + Update Thread indexing + Add loadFromColumm option to Attribute ### 1.0.9 (1/17/17) - Fixes: + All Fastmail domains now use the correct credentials + Offline notification more reliable + Fix error logging ### 1.0.8 (1/17/17) - Introducing Nylas Mail Basic! Read more about it [here](https://blog.nylas.com/nylas-mail-is-now-free-8350d6a1044d) ================================================ FILE: packages/client-app/CONFIGURATION.md ================================================ # Configuration This document outlines configuration options which aren't exposed via N1's preferences interface but may be useful. ## Running Against Open Source Sync Engine If you want to point N1 to your self-hosted sync engine, select "Hosting your own sync engine?" under the "Get Started" button on the welcome screen. There, follow the instructions for creating your own instance of the sync engine and enter the URL and port number where you have it running. ## Other Config Options - `core.workspace.interfaceZoom`: If you'd like the N1 interface to be smaller or larger, this option allows you to scale the UI globally. (Default: 1) ================================================ FILE: packages/client-app/CONTRIBUTING.md ================================================ # Filing an Issue Thanks for checking out N1! If you have a feature request, be sure to check out the [open source roadmap](http://trello.com/b/hxsqB6vx/n1-open-source-roadmap). If someone has already requested the feature you have in mind, you can upvote the card on Trello—to keep things organized, we often close feature requests on GitHub after creating Trello cards. If you've found a bug, try searching for similars issue before filing a new one. Please include the version of N1 you're using, the platform you're using (Mac / Windows / Linux), and the type of email account. (Gmail, Outlook 365, etc.) # Contributing to N1 The hosted sync engine allows us to control adoption of N1 and maintain a great experience for our users. However, the sync engine is [open source](https://github.com/nylas/sync-engine) and you can set it up yourself to begin using N1 immediately. Follow instructions on the [sync engine](https://github.com/nylas/sync-engine) repository. ### Getting Started Before you get started, make sure you've installed the following dependencies. N1's build scripts and tooling use modern JavaScript features and require: - Node 6.0 or above with npm3 - python 2.7 Linux users should make sure they've installed all the packages listed at https://github.com/nylas/nylas-mail/blob/master/.travis.yml#L10. Linux users on Debian 8 and Ubuntu 15.04 onward must also install libgcrypt11 and gnome-keyring. Next, clone and build N1 from source: git clone https://github.com/nylas/nylas-mail.git cd nylas-mail script/bootstrap Read the [getting started guides](https://nylas.github.io/N1/getting-started/). **Building Nylas on Windows? See the [Windows instructions.](https://github.com/nylas/nylas-mail/blob/master/docs/Windows.md)** ### Running N1 npm start ### Testing N1 npm test This will run the full suite of automated unit tests. We use [Jasmine 1.3](http://jasmine.github.io/1.3/introduction.html). It runs all tests inside of the `/spec` folder and all tests inside of `/internal_packages/**/spec` You may skip certain tests (temporarily) with `xit` and `xdescribe`, or focus on only certain tests with `fit` and `fdescribe`. ### Linting N1 N1 lints clean against eslint, coffeelint, csslint, lesslint, and our own internal tool, nylaslint. To run the linters, just run `npm run lint`. ### Creating binaries Once you've checked out N1 and run `script/bootstrap`, you can create a packaged version of the application by running `script/build`. Note that the builds available at [https://nylas.com/N1](https://nylas.com/N1) include licensed fonts, sounds, and other improvements. If you're just looking to run N1, you should download it there! # Pull requests We require all authors sign our [Contributor License Agreement](https://www.nylas.com/cla.html) before pull requests (even minor ones) can be accepted. (It's similar to other projects, like NodeJS Meteor, or React). I'm really sorry, but Legal made us do it. ### Commit Format We decided to not impose super strict commit guidelines on the community. We're trusting you to be thoughtful, responsible, committers. We do have a few heuristics: - Keep commits fairly isolated. Don't jam lots of different functionality in 1 squashed commit. `git bisect` and `git cherry-pick` should still be reasonable things to do. - Keep commits fairly significant. DO `squash` all those little file changes and "fixmes". Don't make it difficult to browse our history. Play the balance between this idea and the last point. If a commit doesn't deserve your time to write a long thoughtful message about, then squash it. - Be hyper-descriptive in your commit messages. I care less about what you did (I can read the code), **I want to know WHY you did it**. Put that in the commit body (not the subject). Itemize the major semantic changes that happened. - Read "[How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/)" if you haven't already (but don't be too prescriptivist about it!) # Running Against Open Source Sync Engine See [Configuration](https://github.com/nylas/nylas-mail/blob/master/CONFIGURATION.md) ================================================ FILE: packages/client-app/LICENSE.md ================================================ MIT License Copyright (c) 2017 Nylas, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/client-app/README.md ================================================ # Nylas Mail - the open-source, extensible mail client ![N1 Screenshot](https://nylas.com/static/img/home/screenshot-hero-mac@2x.png) **Nylas Mail is an open-source mail client built on the modern web with [Electron](https://github.com/atom/electron), [React](https://facebook.github.io/react/), and [Flux](https://facebook.github.io/flux/).** It is designed to be extensible, so it's easy to create new experiences and workflows around email. Want to learn more? Check out the [full documentation](https://nylas.github.io/nylas-mail/). [![Build Status](https://travis-ci.org/nylas/nylas-mail.svg?branch=master)](https://travis-ci.org/nylas/nylas-mail) [![Slack Invite Button](http://slack-invite.nylas.com/badge.svg)](http://slack-invite.nylas.com) #### Want to help build the future of email? [Nylas is hiring](https://jobs.lever.co/nylas)! ## Download Nylas Mail You can download compiled versions of Nylas Mail for Windows, Mac OS X, and Linux (.deb) from [https://nylas.com/download](https://nylas.com/download). You can also build and run Nylas Mail (Previously N1) on Fedora. On Arch Linux, you can install **[n1](https://aur.archlinux.org/packages/n1/)** or **[n1-git](https://aur.archlinux.org/packages/n1-git/)** from the aur. ## Build A Plugin Plugins lie at the heart of Nylas Mail and give it its powerful features. Building your own plugins allows you to integrate the app with other tools, experiment with new workflows, and more. Follow the [Getting Started guide](https://nylas.github.io/nylas-mail/) to write your first plugin in five minutes. To create your own theme, go to our [Theme Starter guide](https://github.com/nylas/N1-theme-starter). If you would like to run the N1 source and contribute, check out our [contributing guide](https://github.com/nylas/nylas-mail/blob/master/CONTRIBUTING.md). ## Themes The Nylas Mail user interface is styled using CSS, which means it's easy to modify and extend. Nylas Mail comes stock with a few beautiful themes, and there are many more which have been built by community developers
#### Bundled Themes - [Dark](https://github.com/nylas/nylas-mail/tree/master/internal_packages/ui-dark) - [Darkside](https://github.com/nylas/nylas-mail/tree/master/internal_packages/ui-darkside) (designed by [Jamie Wilson](https://github.com/jamiewilson)) - [Taiga](https://github.com/nylas/nylas-mail/tree/master/internal_packages/ui-taiga) (designed by [Noah Buscher](https://github.com/noahbuscher)) - [Ubuntu](https://github.com/nylas/nylas-mail/tree/master/internal_packages/ui-ubuntu) (designed by [Ahmed Elhanafy](https://github.com/ahmedlhanafy)) - [Less Is More](https://github.com/nylas/nylas-mail/tree/master/internal_packages/ui-less-is-more) (designed by [Alexander Adkins](https://github.com/P0WW0W)) #### Community Themes - [Arc Dark](https://github.com/varlesh/Nylas-Arc-Dark-Theme) - [Predawn](https://github.com/adambmedia/N1-Predawn) - [ElementaryOS](https://github.com/edipox/elementary-nylas) - [Ido](https://github.com/edipox/n1-ido)—Polymail-inspired theme - [Solarized Dark](https://github.com/NSHenry/N1-Solarized-Dark) - [Berend](https://github.com/Frique/N1-Berend) - [LevelUp](https://github.com/stolinski/level-up-nylas-n1-theme) - [Sunrise](https://github.com/jackiehluo/n1-sunrise) - [ToogaBooga](https://github.com/brycedorn/N1-ToogaBooga) - [Material](https://github.com/jackiehluo/n1-material) - [Monokai](https://github.com/dcondrey/n1-monokai) - [Agapanthus](https://github.com/taniadaniela/n1-agapanthus)—Inbox-inspired theme - [Stripe](https://github.com/oeaeee/n1-stripe) - [Kleinstein] (https://github.com/diklein/Kleinstein)—Hide the account list sidebar - [BoraBora](https://github.com/arimai/N1-BoraBora) - [Honeyduke](https://github.com/arimai/n1-honeyduke) - [Snow](https://github.com/Wattenberger/N1-snow-theme) - [Hull](https://github.com/unity/n1-hull) - [Express](https://github.com/oeaeee/n1-express) - [DarkSoda](https://github.com/adambullmer/N1-theme-DarkSoda) - [Bemind](https://github.com/bemindinteractive/Bemind-N1-Theme) - [Dracula](https://github.com/dracula/nylas-n1) - [MouseEatsCat](https://github.com/MouseEatsCat/MouseEatsCat-N1) - [Sublime Dark](https://github.com/rishabhkesarwani/Nylas-Sublime-Dark-Theme) - [Firefox](https://github.com/darshandsoni/n1-firefox-theme) - [Gmail](https://github.com/dregitsky/n1-gmail-theme) - [Darkish](https://github.com/dyrnade/N1-Darkish) #### To install community themes: 1. Download and unzip the repo 2. In Nylas Mail, select `Developer > Install a Package Manually... ` 3. Navigate to where you downloaded the theme and select the root folder. The theme is copied into the `~/.nylas-mail` folder for your convinence 5. Select `Change Theme...` from the top level menu, and you'll see the newly installed theme. That's it! Want to dive in more? Try [creating your own theme](https://github.com/nylas/nylas-mail-theme-starter)! ## Plugin List We're working on building a plugin index that makes it super easy to add them to Nylas Mail. For now, check out the list below! (Feel free to submit a PR if you build a plugin and want it featured here.) #### Bundled Plugins Great starting points for creating your own plugins! - [Translate](https://github.com/nylas/nylas-mail/tree/master/internal_packages/composer-translate)—Works with 10 languages - [Quick Replies](https://github.com/nylas/nylas-mail/tree/master/internal_packages/composer-templates)—Send emails faster with templates - [Emoji Keyboard](https://github.com/nylas/nylas-mail/tree/master/internal_packages/composer-emoji)—Insert emoji by typing a colon (:) followed by the name of an emoji symbol - [GitHub Sidebar Info](https://github.com/nylas/nylas-mail/tree/master/internal_packages/github-contact-card) - [View on GitHub](https://github.com/nylas/nylas-mail/tree/master/internal_packages/message-view-on-github) - [Personal Level Indicators](https://github.com/nylas/nylas-mail/tree/master/internal_packages/personal-level-indicators) - [Phishing Detection](https://github.com/nylas/nylas-mail/tree/master/internal_packages/phishing-detection) #### Community Plugins Note these are not tested or officially supported by Nylas, but we still think they are really cool! If you find bugs with them, please open GitHub issues on their individual project pages, not the Nylas Mail (N1) repo page. Thanks! - [Jiffy](http://noahbuscher.github.io/N1-Jiffy/)—Insert animated GIFs - [Weather](https://github.com/jackiehluo/n1-weather) - [Todoist](https://github.com/alexfruehwirth/N1TodoistIntegration) - [Unsubscribe](https://github.com/colinking/n1-unsubscribe) - [Squirt Speed Reader](https://github.com/HarleyKwyn/squirt-reader-N1-plugin/) - [Website Launcher](https://github.com/adriangrantdotorg/nylas-n1-background-webpage)—Opens a URL in separate window - In Development: [Cypher](https://github.com/mbilker/cypher) (PGP Encryption) - [Avatars](https://github.com/unity/n1-avatars) - [Events Calendar (WIP)](https://github.com/nerdenough/n1-events-calendar) - [Mail in Chat (WIP)](https://github.com/yjchen/mail_in_chat) - [Evernote](https://github.com/grobgl/n1-evernote) - [Wunderlist](https://github.com/miguelrs/n1-wunderlist) - [Participants Display](https://github.com/kbruccoleri/nylas-participants-display) - [GitHub](https://github.com/ForbesLindesay/N1-GitHub) When you install packages, they're moved to ~/.nylas-mail/packages, and Nylas Mail runs apm install on the command line to fetch dependencies listed in the package's package.json ## Building the docs Plugin SDK docs are available at [https://nylas.github.io/nylas-mail/](https://nylas.github.io/nylas-mail/). Here's how you build them: Until my patch gets merged, docs need to be built manually using mg's fork. git clone git@github.com:grinich/gitbook.git cd nylas-mail ./node_modules/.bin/gitbook alias ../gitbook latest Then to actually build the docs: script/grunt docs ./node_modules/.bin/gitbook --gitbook=latest build . ./_docs_output --log=debug --debug rm -r docs_src/classes If you want to preview the docs: pushd ./_docs_output; python -m SimpleHTTPServer; popd Just want to publish everything? There's a helper script that does it for you: script/publish-docs ## Configuration You can configure Nylas Mail in a few ways—for instance, pointing it to your self-hosted instance of the sync engine or changing the interface zoom level. [Learn more about how.](https://github.com/nylas/nylas-mail/blob/master/CONFIGURATION.md) ## Feature Requests / Plugin Ideas Have an idea for a package or a feature you'd love to see in Nylas Mail? Search for existing [GitHub issues](https://github.com/nylas/nylas-mail/issues) and join the conversation! ================================================ FILE: packages/client-app/apm/README.md ================================================ Nylas Mail ships a copy of [apm](https://github.com/atom/apm) to build packages when users choose to install them. This won't be true much longer. ================================================ FILE: packages/client-app/apm/package.json ================================================ { "name": "n1-bundled-apm", "description": "N1's bundled apm", "repository": { "type": "git", "url": "https://github.com/nylas/nylas-mail" }, "dependencies": { "atom-package-manager": "1.1.1" } } ================================================ FILE: packages/client-app/build/Gruntfile.js ================================================ /* eslint global-require: 0 */ /* eslint import/no-dynamic-require: 0 */ const path = require('path'); module.exports = (grunt) => { if (!grunt.option('platform')) { grunt.option('platform', process.platform); } /** * The main appDir is that of the root nylas-mail-all repo. This Gruntfile * is designed to be run from the npm-build-client task whose repo root is * the main nylas-mail-all package. */ const appDir = path.resolve(path.join('packages', 'client-app')); const buildDir = path.join(appDir, 'build'); const tasksDir = path.join(buildDir, 'tasks'); const taskHelpers = require(path.join(tasksDir, 'task-helpers'))(grunt) // This allows all subsequent paths to the relative to the root of the repo grunt.config.init({ 'taskHelpers': taskHelpers, 'rootDir': path.resolve('./'), 'buildDir': buildDir, 'appDir': appDir, 'classDocsOutputDir': './docs_src/classes', 'outputDir': path.join(appDir, 'dist'), 'appJSON': grunt.file.readJSON(path.join(appDir, 'package.json')), 'source:coffeescript': [ 'internal_packages/**/*.cjsx', 'internal_packages/**/*.coffee', 'dot-nylas/**/*.coffee', 'src/**/*.coffee', 'src/**/*.cjsx', '!src/**/node_modules/**/*.coffee', '!internal_packages/**/node_modules/**/*.coffee', ], 'source:es6': [ 'internal_packages/**/*.jsx', 'internal_packages/**/*.es6', 'internal_packages/**/*.es', 'dot-nylas/**/*.es6', 'dot-nylas/**/*.es', 'src/**/*.es6', 'src/**/*.es', 'src/**/*.jsx', 'src/K2/**/*.js', // K2 doesn't use ES6 extension, lint it anyway! '!src/K2/packages/local-private/src/error-logger-extensions/*.js', '!src/**/node_modules/**/*.es6', '!src/**/node_modules/**/*.es', '!src/**/node_modules/**/*.jsx', '!src/K2/**/node_modules/**/*.js', '!internal_packages/**/node_modules/**/*.es6', '!internal_packages/**/node_modules/**/*.es', '!internal_packages/**/node_modules/**/*.jsx', ], }); grunt.loadTasks(tasksDir); grunt.file.setBase(appDir); grunt.registerTask('docs', ['docs-build', 'docs-render']); grunt.registerTask('lint', [ 'eslint', 'lesslint', 'nylaslint', 'coffeelint', 'csslint', ]); if (grunt.option('platform') === 'win32') { grunt.registerTask("build-client", [ "package", // The Windows electron-winstaller task must be run outside of grunt ]); } else if (grunt.option('platform') === 'darwin') { grunt.registerTask("build-client", [ "package", "create-mac-zip", "create-mac-dmg", ]); } else if (grunt.option('platform') === 'linux') { grunt.registerTask("build-client", [ "package", "create-deb-installer", "create-rpm-installer", ]); } } ================================================ FILE: packages/client-app/build/README.md ================================================ # N1 Build Environment Node version 0.10.x (Due to the version of electron currently used.) # N1 Building and Tasks This folder contains tasks to create production builds of N1 Tasks should not be executed from this folder, but rather from `/scripts`. The `/scripts` folder has convenient methods that fix paths and do environment checks. Note that most of the task definitions are stored in `/build/tasks` ## Some useful tasks NOTE: Run all of these from the N1 root folder. **Linting:** `script/grunt lint` **Building:** `script/grunt build` The build folder has its own package.json and is isolated so we can use `npm` to compile against v8's headers instead of `apm` ================================================ FILE: packages/client-app/build/config/coffeelint.json ================================================ { "max_line_length": { "level": "ignore" }, "no_empty_param_list": { "level": "error" }, "arrow_spacing": { "level": "error" }, "no_unnecessary_fat_arrows": { "level": "ignore" }, "no_interpolation_in_single_quotes": { "level": "error" }, "no_debugger": { "level": "error" } } ================================================ FILE: packages/client-app/build/docs_templates/_function.html ================================================

{{name}}({{#each arguments}}{{#if isOptional}}[{{/if}}{{name}}{{#if isOptional}}]{{/if}}{{/each}})

{{{description}}}

{{#if arguments.length}} Parameters {{#each arguments}} {{/each}}
Argument Description
{{name}} {{#if isOptional}}Optional{{/if}} {{{description}}}
{{/if}} {{#if returnValues.length}} Returns {{#each returnValues}} {{/each}}
Return Values
{{{description}}}
{{/if}} ================================================ FILE: packages/client-app/build/docs_templates/_property.html ================================================

{{name}}

{{{description}}}

{{#if arguments.length}} {{#each arguments}} {{/each}}
{{name}} {{#if isOptional}}Optional{{/if}} {{{description}}}
{{/if}} ================================================ FILE: packages/client-app/build/docs_templates/class.md ================================================ # {{ name }} ## Summary {{{documentation.description}}} {{#if documentation.classProperties.length}} ### Class Properties {{#each documentation.classProperties}} {{> _property.html}} {{/each}} {{/if}} {{#if documentation.classMethods.length}} ### Class Methods {{#each documentation.classMethods}} {{> _function.html}} {{/each}} {{/if}} {{#if documentation.instanceMethods.length}} ### Instance Methods {{#each documentation.instanceMethods}} {{> _function.html}} {{/each}} {{/if}} ================================================ FILE: packages/client-app/build/docs_templates/sidebar.md ================================================ {{!-- This is our preferred ordering, so do it manually! --}} ## General {{#each sidebar.General}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Component Kit {{#each sidebar.[Component Kit]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Extensions {{#each sidebar.[Extensions]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Models {{#each sidebar.[Models]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Stores {{#each sidebar.[Stores]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Database {{#each sidebar.[Database]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Drafts {{#each sidebar.[Drafts]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## NylasEnv {{#each sidebar.[NylasEnv]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ## Atom {{#each sidebar.[Atom]}} * [{{this}}](/classes/{{this}}.md) {{/each}} ================================================ FILE: packages/client-app/build/resources/asar-ordering-hint.txt ================================================ 956764: package.json 1760546: src/browser/main.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 1853312: node_modules/fs-plus/node_modules/async/package.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1894875: node_modules/mkdirp/package.json 1896279: node_modules/mkdirp/index.js 1898909: node_modules/optimist/package.json 1900199: node_modules/optimist/index.js 1914385: node_modules/optimist/node_modules/wordwrap/package.json 1915858: node_modules/optimist/node_modules/wordwrap/index.js 1918089: src/error-logger.js 1926560: node_modules/nslog/package.json 1928316: node_modules/nslog/lib/nslog.js 1928640: src/error-logger-extensions/nylas-private-error-reporter.js 1933337: node_modules/raven/package.json 1935222: node_modules/raven/index.js 1935631: node_modules/raven/lib/client.js 1941308: node_modules/raven/lib/parsers.js 1945141: node_modules/raven/node_modules/cookie/package.json 1946217: node_modules/raven/node_modules/cookie/index.js 1948116: node_modules/raven/lib/utils.js 1953762: node_modules/raven/lib/transports.js 1956068: node_modules/raven/node_modules/lsmod/package.json 1957254: node_modules/raven/node_modules/lsmod/index.js 1958729: node_modules/raven/node_modules/stack-trace/package.json 1960042: node_modules/raven/node_modules/stack-trace/lib/stack-trace.js 1962761: node_modules/node-uuid/package.json 1964629: node_modules/node-uuid/uuid.js 1933337: node_modules/raven/package.json 1972642: node_modules/raven/lib/middleware/connect.js 1973294: src/compile-cache.js 1978902: src/compile-support/babel.js 1980527: static/babelrc.json 1980671: src/compile-support/coffee-script.js 1981853: src/compile-support/typescript.js 1983139: node_modules/underscore/package.json 1985095: node_modules/underscore/underscore.js 2038014: node_modules/source-map-support/package.json 2039642: node_modules/source-map-support/source-map-support.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 2130092: src/browser/application.js 2161879: src/browser/system-tray-manager.js 2173675: src/browser/nylas-window.js 2187662: src/browser/window-manager.js 91213297: src/browser/window-launcher.js 91200495: src/browser/file-list-cache.js 2195924: src/browser/application-menu.js 2207382: src/flux/models/utils.js 8174990: node_modules/moment-timezone/package.json 8177056: node_modules/moment-timezone/index.js 8177170: node_modules/moment-timezone/moment-timezone.js 3971136: node_modules/moment/package.json 3974612: node_modules/moment/moment.js 8190929: node_modules/moment-timezone/data/packed/latest.json 3261374: src/task-registry.js 3264167: src/serializable-registry.js 3271782: src/database-object-registry.js 2228693: src/browser/auto-update-manager.js 2235663: src/browser/nylas-protocol-handler.js 2396007: node_modules/season/package.json 2397840: node_modules/season/lib/cson.js 2238228: src/config.js 2261295: src/config-utils.js 2264399: node_modules/emissary/package.json 2266273: node_modules/emissary/lib/emissary.js 2266555: node_modules/emissary/lib/helpers.js 2268129: node_modules/emissary/lib/behavior.js 2272107: node_modules/emissary/node_modules/underscore-plus/package.json 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2288860: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/package.json 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2336063: node_modules/property-accessors/package.json 2337929: node_modules/property-accessors/lib/property-accessors.js 2340201: node_modules/property-accessors/node_modules/mixto/package.json 2341779: node_modules/property-accessors/node_modules/mixto/lib/mixin.js 2343179: node_modules/emissary/lib/signal.js 2352520: node_modules/emissary/lib/emitter.js 2367779: node_modules/emissary/node_modules/mixto/package.json 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 2376215: node_modules/event-kit/package.json 2378208: node_modules/event-kit/lib/event-kit.js 2378397: node_modules/event-kit/lib/emitter.js 2382101: node_modules/event-kit/lib/disposable.js 2394595: node_modules/event-kit/lib/composite-disposable.js 2441735: node_modules/pathwatcher/package.json 2444020: node_modules/pathwatcher/lib/main.js 2450494: node_modules/pathwatcher/lib/file.js 2466571: node_modules/pathwatcher/node_modules/underscore-plus/package.json 2468584: node_modules/pathwatcher/node_modules/underscore-plus/lib/underscore-plus.js 2483372: node_modules/pathwatcher/node_modules/underscore-plus/node_modules/underscore/package.json 2485130: node_modules/pathwatcher/node_modules/underscore-plus/node_modules/underscore/underscore.js 2530619: node_modules/pathwatcher/lib/directory.js 2542040: node_modules/pathwatcher/node_modules/async/package.json 2543482: node_modules/pathwatcher/node_modules/async/lib/async.js 2572883: src/color.js 1973294: src/compile-cache.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 1973294: src/compile-cache.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 1973294: src/compile-cache.js 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 1853312: node_modules/fs-plus/node_modules/async/package.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1978902: src/compile-support/babel.js 1853312: node_modules/fs-plus/node_modules/async/package.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1853312: node_modules/fs-plus/node_modules/async/package.json 1980527: static/babelrc.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1980671: src/compile-support/coffee-script.js 1981853: src/compile-support/typescript.js 1978902: src/compile-support/babel.js 1983139: node_modules/underscore/package.json 1985095: node_modules/underscore/underscore.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1978902: src/compile-support/babel.js 1980527: static/babelrc.json 1980671: src/compile-support/coffee-script.js 1981853: src/compile-support/typescript.js 2038014: node_modules/source-map-support/package.json 1983139: node_modules/underscore/package.json 2039642: node_modules/source-map-support/source-map-support.js 1985095: node_modules/underscore/underscore.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 1980527: static/babelrc.json 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 1980671: src/compile-support/coffee-script.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 1981853: src/compile-support/typescript.js 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 1983139: node_modules/underscore/package.json 1985095: node_modules/underscore/underscore.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2038014: node_modules/source-map-support/package.json 2039642: node_modules/source-map-support/source-map-support.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2038014: node_modules/source-map-support/package.json 2039642: node_modules/source-map-support/source-map-support.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 2851648: src/module-cache.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2866883: node_modules/semver/package.json 2868219: node_modules/semver/semver.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 956764: package.json 2851648: src/module-cache.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2866883: node_modules/semver/package.json 2868219: node_modules/semver/semver.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 2851648: src/module-cache.js 956764: package.json 2866883: node_modules/semver/package.json 2868219: node_modules/semver/semver.js 956764: package.json 2397840: node_modules/season/lib/cson.js 94886363: src/secondary-window-bootstrap.js 2901212: node_modules/bluebird/js/main/bluebird.js 2901506: node_modules/bluebird/js/main/promise.js 2926597: node_modules/bluebird/js/main/util.js 2935230: node_modules/bluebird/js/main/es5.js 2397840: node_modules/season/lib/cson.js 2937208: node_modules/bluebird/js/main/async.js 2925857: src/window-bootstrap.js 2941161: node_modules/bluebird/js/main/schedule.js 2901212: node_modules/bluebird/js/main/bluebird.js 2901506: node_modules/bluebird/js/main/promise.js 2942440: node_modules/bluebird/js/main/queue.js 2944794: node_modules/bluebird/js/main/errors.js 2948412: node_modules/bluebird/js/main/thenables.js 2950756: node_modules/bluebird/js/main/promise_array.js 2926597: node_modules/bluebird/js/main/util.js 2954903: node_modules/bluebird/js/main/captured_trace.js 2935230: node_modules/bluebird/js/main/es5.js 2397840: node_modules/season/lib/cson.js 2937208: node_modules/bluebird/js/main/async.js 94886363: src/secondary-window-bootstrap.js 2941161: node_modules/bluebird/js/main/schedule.js 2901212: node_modules/bluebird/js/main/bluebird.js 2942440: node_modules/bluebird/js/main/queue.js 2901506: node_modules/bluebird/js/main/promise.js 2969949: node_modules/bluebird/js/main/debuggability.js 2944794: node_modules/bluebird/js/main/errors.js 2975097: node_modules/bluebird/js/main/context.js 2948412: node_modules/bluebird/js/main/thenables.js 2976035: node_modules/bluebird/js/main/catch_filter.js 2950756: node_modules/bluebird/js/main/promise_array.js 2978109: node_modules/bluebird/js/main/promise_resolver.js 2926597: node_modules/bluebird/js/main/util.js 2954903: node_modules/bluebird/js/main/captured_trace.js 2981972: node_modules/bluebird/js/main/progress.js 2935230: node_modules/bluebird/js/main/es5.js 2984464: node_modules/bluebird/js/main/method.js 2985800: node_modules/bluebird/js/main/bind.js 2987812: node_modules/bluebird/js/main/finally.js 2937208: node_modules/bluebird/js/main/async.js 2990436: node_modules/bluebird/js/main/direct_resolve.js 2991902: node_modules/bluebird/js/main/synchronous_inspection.js 2941161: node_modules/bluebird/js/main/schedule.js 2942440: node_modules/bluebird/js/main/queue.js 2994543: node_modules/bluebird/js/main/join.js 2969949: node_modules/bluebird/js/main/debuggability.js 2998433: node_modules/bluebird/js/main/map.js 2944794: node_modules/bluebird/js/main/errors.js 2975097: node_modules/bluebird/js/main/context.js 3002811: node_modules/bluebird/js/main/cancel.js 2948412: node_modules/bluebird/js/main/thenables.js 2976035: node_modules/bluebird/js/main/catch_filter.js 3004209: node_modules/bluebird/js/main/using.js 2950756: node_modules/bluebird/js/main/promise_array.js 2978109: node_modules/bluebird/js/main/promise_resolver.js 2954903: node_modules/bluebird/js/main/captured_trace.js 3011204: node_modules/bluebird/js/main/generators.js 2981972: node_modules/bluebird/js/main/progress.js 2984464: node_modules/bluebird/js/main/method.js 3015905: node_modules/bluebird/js/main/nodeify.js 2985800: node_modules/bluebird/js/main/bind.js 3017541: node_modules/bluebird/js/main/call_get.js 2987812: node_modules/bluebird/js/main/finally.js 3021885: node_modules/bluebird/js/main/props.js 2990436: node_modules/bluebird/js/main/direct_resolve.js 2991902: node_modules/bluebird/js/main/synchronous_inspection.js 3024057: node_modules/bluebird/js/main/race.js 2994543: node_modules/bluebird/js/main/join.js 3025282: node_modules/bluebird/js/main/reduce.js 2969949: node_modules/bluebird/js/main/debuggability.js 2998433: node_modules/bluebird/js/main/map.js 3030305: node_modules/bluebird/js/main/settle.js 2975097: node_modules/bluebird/js/main/context.js 3031473: node_modules/bluebird/js/main/some.js 2976035: node_modules/bluebird/js/main/catch_filter.js 3002811: node_modules/bluebird/js/main/cancel.js 3004209: node_modules/bluebird/js/main/using.js 2978109: node_modules/bluebird/js/main/promise_resolver.js 3034851: node_modules/bluebird/js/main/promisify.js 2981972: node_modules/bluebird/js/main/progress.js 3011204: node_modules/bluebird/js/main/generators.js 2984464: node_modules/bluebird/js/main/method.js 3046413: node_modules/bluebird/js/main/any.js 3015905: node_modules/bluebird/js/main/nodeify.js 3046834: node_modules/bluebird/js/main/each.js 2985800: node_modules/bluebird/js/main/bind.js 3047132: node_modules/bluebird/js/main/timers.js 3017541: node_modules/bluebird/js/main/call_get.js 2987812: node_modules/bluebird/js/main/finally.js 3048873: node_modules/bluebird/js/main/filter.js 2990436: node_modules/bluebird/js/main/direct_resolve.js 3021885: node_modules/bluebird/js/main/props.js 2991902: node_modules/bluebird/js/main/synchronous_inspection.js 2994543: node_modules/bluebird/js/main/join.js 3024057: node_modules/bluebird/js/main/race.js 3025282: node_modules/bluebird/js/main/reduce.js 2998433: node_modules/bluebird/js/main/map.js 2937208: node_modules/bluebird/js/main/async.js 3049187: node_modules/babel-core/package.json 3030305: node_modules/bluebird/js/main/settle.js 3002811: node_modules/bluebird/js/main/cancel.js 3031473: node_modules/bluebird/js/main/some.js 3004209: node_modules/bluebird/js/main/using.js 3034851: node_modules/bluebird/js/main/promisify.js 3011204: node_modules/bluebird/js/main/generators.js 1973294: src/compile-cache.js 3015905: node_modules/bluebird/js/main/nodeify.js 3046413: node_modules/bluebird/js/main/any.js 3046834: node_modules/bluebird/js/main/each.js 3017541: node_modules/bluebird/js/main/call_get.js 3047132: node_modules/bluebird/js/main/timers.js 3021885: node_modules/bluebird/js/main/props.js 2901506: node_modules/bluebird/js/main/promise.js 3048873: node_modules/bluebird/js/main/filter.js 3024057: node_modules/bluebird/js/main/race.js 3025282: node_modules/bluebird/js/main/reduce.js 2937208: node_modules/bluebird/js/main/async.js 3030305: node_modules/bluebird/js/main/settle.js 2901212: node_modules/bluebird/js/main/bluebird.js 3049187: node_modules/babel-core/package.json 3031473: node_modules/bluebird/js/main/some.js 2926597: node_modules/bluebird/js/main/util.js 3034851: node_modules/bluebird/js/main/promisify.js 3046413: node_modules/bluebird/js/main/any.js 3052709: src/window.js 3046834: node_modules/bluebird/js/main/each.js 3053190: src/nylas-env.js 1973294: src/compile-cache.js 3047132: node_modules/bluebird/js/main/timers.js 3048873: node_modules/bluebird/js/main/filter.js 2901506: node_modules/bluebird/js/main/promise.js 2937208: node_modules/bluebird/js/main/async.js 3049187: node_modules/babel-core/package.json 2901212: node_modules/bluebird/js/main/bluebird.js 2926597: node_modules/bluebird/js/main/util.js 1973294: src/compile-cache.js 2266273: node_modules/emissary/lib/emissary.js 2266555: node_modules/emissary/lib/helpers.js 3052709: src/window.js 2268129: node_modules/emissary/lib/behavior.js 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2901506: node_modules/bluebird/js/main/promise.js 3053190: src/nylas-env.js 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2901212: node_modules/bluebird/js/main/bluebird.js 2926597: node_modules/bluebird/js/main/util.js 2266273: node_modules/emissary/lib/emissary.js 3052709: src/window.js 2266555: node_modules/emissary/lib/helpers.js 3053190: src/nylas-env.js 2268129: node_modules/emissary/lib/behavior.js 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2337929: node_modules/property-accessors/lib/property-accessors.js 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2343179: node_modules/emissary/lib/signal.js 2352520: node_modules/emissary/lib/emitter.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 2266273: node_modules/emissary/lib/emissary.js 2266555: node_modules/emissary/lib/helpers.js 2268129: node_modules/emissary/lib/behavior.js 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2378208: node_modules/event-kit/lib/event-kit.js 2337929: node_modules/property-accessors/lib/property-accessors.js 2378397: node_modules/event-kit/lib/emitter.js 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2382101: node_modules/event-kit/lib/disposable.js 2343179: node_modules/emissary/lib/signal.js 2394595: node_modules/event-kit/lib/composite-disposable.js 3088814: node_modules/coffeestack/index.js 2352520: node_modules/emissary/lib/emitter.js 3093983: src/window-event-handler.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 2378208: node_modules/event-kit/lib/event-kit.js 2337929: node_modules/property-accessors/lib/property-accessors.js 3106501: src/styles-element.js 2378397: node_modules/event-kit/lib/emitter.js 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2382101: node_modules/event-kit/lib/disposable.js 94901394: src/store-registry.js 2343179: node_modules/emissary/lib/signal.js 2394595: node_modules/event-kit/lib/composite-disposable.js 3264167: src/serializable-registry.js 3088814: node_modules/coffeestack/index.js 2352520: node_modules/emissary/lib/emitter.js 3093983: src/window-event-handler.js 2207382: src/flux/models/utils.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 8174990: node_modules/moment-timezone/package.json 8177056: node_modules/moment-timezone/index.js 8177170: node_modules/moment-timezone/moment-timezone.js 2378208: node_modules/event-kit/lib/event-kit.js 2378397: node_modules/event-kit/lib/emitter.js 3974612: node_modules/moment/moment.js 3106501: src/styles-element.js 2382101: node_modules/event-kit/lib/disposable.js 2394595: node_modules/event-kit/lib/composite-disposable.js 94901394: src/store-registry.js 3088814: node_modules/coffeestack/index.js 3264167: src/serializable-registry.js 3093983: src/window-event-handler.js 2207382: src/flux/models/utils.js 8174990: node_modules/moment-timezone/package.json 8177056: node_modules/moment-timezone/index.js 8177170: node_modules/moment-timezone/moment-timezone.js 3106501: src/styles-element.js 3974612: node_modules/moment/moment.js 94901394: src/store-registry.js 3264167: src/serializable-registry.js 2207382: src/flux/models/utils.js 8174990: node_modules/moment-timezone/package.json 8177056: node_modules/moment-timezone/index.js 8177170: node_modules/moment-timezone/moment-timezone.js 3974612: node_modules/moment/moment.js 8190929: node_modules/moment-timezone/data/packed/latest.json 8190929: node_modules/moment-timezone/data/packed/latest.json 8190929: node_modules/moment-timezone/data/packed/latest.json 3261374: src/task-registry.js 3271782: src/database-object-registry.js 3113921: src/flux/errors.js 3261374: src/task-registry.js 3271782: src/database-object-registry.js 3113921: src/flux/errors.js 3261374: src/task-registry.js 1918089: src/error-logger.js 1918089: src/error-logger.js 3271782: src/database-object-registry.js 3113921: src/flux/errors.js 1928640: src/error-logger-extensions/nylas-private-error-reporter.js 1933337: node_modules/raven/package.json 1928640: src/error-logger-extensions/nylas-private-error-reporter.js 1935222: node_modules/raven/index.js 1935631: node_modules/raven/lib/client.js 1933337: node_modules/raven/package.json 1935222: node_modules/raven/index.js 1941308: node_modules/raven/lib/parsers.js 1935631: node_modules/raven/lib/client.js 1946217: node_modules/raven/node_modules/cookie/index.js 1948116: node_modules/raven/lib/utils.js 1941308: node_modules/raven/lib/parsers.js 1953762: node_modules/raven/lib/transports.js 1946217: node_modules/raven/node_modules/cookie/index.js 1948116: node_modules/raven/lib/utils.js 1953762: node_modules/raven/lib/transports.js 1918089: src/error-logger.js 1928640: src/error-logger-extensions/nylas-private-error-reporter.js 1933337: node_modules/raven/package.json 1935222: node_modules/raven/index.js 1935631: node_modules/raven/lib/client.js 1941308: node_modules/raven/lib/parsers.js 1946217: node_modules/raven/node_modules/cookie/index.js 1948116: node_modules/raven/lib/utils.js 1953762: node_modules/raven/lib/transports.js 1957254: node_modules/raven/node_modules/lsmod/index.js 1957254: node_modules/raven/node_modules/lsmod/index.js 1960042: node_modules/raven/node_modules/stack-trace/lib/stack-trace.js 1960042: node_modules/raven/node_modules/stack-trace/lib/stack-trace.js 1964629: node_modules/node-uuid/uuid.js 1964629: node_modules/node-uuid/uuid.js 1933337: node_modules/raven/package.json 1933337: node_modules/raven/package.json 1972642: node_modules/raven/lib/middleware/connect.js 1972642: node_modules/raven/lib/middleware/connect.js 1957254: node_modules/raven/node_modules/lsmod/index.js 1960042: node_modules/raven/node_modules/stack-trace/lib/stack-trace.js 1964629: node_modules/node-uuid/uuid.js 1933337: node_modules/raven/package.json 1972642: node_modules/raven/lib/middleware/connect.js 2238228: src/config.js 2238228: src/config.js 2261295: src/config-utils.js 2261295: src/config-utils.js 2444020: node_modules/pathwatcher/lib/main.js 2444020: node_modules/pathwatcher/lib/main.js 2450494: node_modules/pathwatcher/lib/file.js 2450494: node_modules/pathwatcher/lib/file.js 2530619: node_modules/pathwatcher/lib/directory.js 2530619: node_modules/pathwatcher/lib/directory.js 2572883: src/color.js 2572883: src/color.js 2238228: src/config.js 3115571: src/keymap-manager.js 3115571: src/keymap-manager.js 2261295: src/config-utils.js 72365667: node_modules/mousetrap/mousetrap.js 72365667: node_modules/mousetrap/mousetrap.js 2444020: node_modules/pathwatcher/lib/main.js 3122755: src/command-registry.js 3122755: src/command-registry.js 3153088: src/package-manager.js 3153088: src/package-manager.js 2450494: node_modules/pathwatcher/lib/file.js 3176053: node_modules/q/q.js 3176053: node_modules/q/q.js 2530619: node_modules/pathwatcher/lib/directory.js 2572883: src/color.js 3115571: src/keymap-manager.js 72365667: node_modules/mousetrap/mousetrap.js 3122755: src/command-registry.js 3176053: node_modules/q/q.js 3176053: node_modules/q/q.js 3153088: src/package-manager.js 3153088: src/package-manager.js 3153088: src/package-manager.js 3053190: src/nylas-env.js 3053190: src/nylas-env.js 3176053: node_modules/q/q.js 94886363: src/secondary-window-bootstrap.js 2925857: src/window-bootstrap.js 3238845: src/package.js 3238845: src/package.js 2407083: node_modules/async/lib/async.js 2407083: node_modules/async/lib/async.js 3176053: node_modules/q/q.js 3274725: src/theme-package.js 3274725: src/theme-package.js 3276790: src/flux/stores/database-store.js 3276790: src/flux/stores/database-store.js 3153088: src/package-manager.js 3053190: src/nylas-env.js 94886363: src/secondary-window-bootstrap.js 2405266: node_modules/async/package.json 2405266: node_modules/async/package.json 3305440: node_modules/sqlite3/package.json 3305440: node_modules/sqlite3/package.json 3317559: node_modules/sqlite3/lib/sqlite3.js 3317559: node_modules/sqlite3/lib/sqlite3.js 3323109: node_modules/node-pre-gyp/lib/node-pre-gyp.js 3323109: node_modules/node-pre-gyp/lib/node-pre-gyp.js 3238845: src/package.js 74661469: node_modules/nopt/lib/nopt.js 74661469: node_modules/nopt/lib/nopt.js 41220040: node_modules/abbrev/abbrev.js 41220040: node_modules/abbrev/abbrev.js 2407083: node_modules/async/lib/async.js 74736261: node_modules/npmlog/log.js 74736261: node_modules/npmlog/log.js 41757580: node_modules/are-we-there-yet/index.js 41757580: node_modules/are-we-there-yet/index.js 41760200: node_modules/are-we-there-yet/tracker-group.js 41760200: node_modules/are-we-there-yet/tracker-group.js 41759926: node_modules/are-we-there-yet/tracker-base.js 41759926: node_modules/are-we-there-yet/tracker-base.js 41764374: node_modules/are-we-there-yet/tracker.js 41764374: node_modules/are-we-there-yet/tracker.js 41763431: node_modules/are-we-there-yet/tracker-stream.js 41763431: node_modules/are-we-there-yet/tracker-stream.js 3327439: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/readable.js 3327439: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/readable.js 3327909: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_readable.js 3274725: src/theme-package.js 3327909: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_readable.js 3276790: src/flux/stores/database-store.js 56978227: node_modules/falafel/node_modules/isarray/index.js 56978227: node_modules/falafel/node_modules/isarray/index.js 56174974: node_modules/core-util-is/lib/util.js 56174974: node_modules/core-util-is/lib/util.js 3357009: node_modules/babel-core/node_modules/regenerator/node_modules/commoner/node_modules/glob/node_modules/inherits/inherits.js 3357009: node_modules/babel-core/node_modules/regenerator/node_modules/commoner/node_modules/glob/node_modules/inherits/inherits.js 3357051: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_writable.js 2405266: node_modules/async/package.json 3357051: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_writable.js 3305440: node_modules/sqlite3/package.json 3317559: node_modules/sqlite3/lib/sqlite3.js 3370120: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_duplex.js 3370120: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_duplex.js 3372931: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_transform.js 3323109: node_modules/node-pre-gyp/lib/node-pre-gyp.js 3372931: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_transform.js 3380281: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_passthrough.js 74661469: node_modules/nopt/lib/nopt.js 3380281: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_passthrough.js 56223160: node_modules/delegates/index.js 56223160: node_modules/delegates/index.js 41220040: node_modules/abbrev/abbrev.js 57167856: node_modules/gauge/progress-bar.js 57167856: node_modules/gauge/progress-bar.js 74736261: node_modules/npmlog/log.js 57204450: node_modules/has-unicode/index.js 57204450: node_modules/has-unicode/index.js 41738129: node_modules/ansi/lib/ansi.js 41738129: node_modules/ansi/lib/ansi.js 41757580: node_modules/are-we-there-yet/index.js 41760200: node_modules/are-we-there-yet/tracker-group.js 41759926: node_modules/are-we-there-yet/tracker-base.js 41746103: node_modules/ansi/lib/newlines.js 41746103: node_modules/ansi/lib/newlines.js 41764374: node_modules/are-we-there-yet/tracker.js 41763431: node_modules/are-we-there-yet/tracker-stream.js 3327439: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/readable.js 67599487: node_modules/lodash.pad/index.js 67599487: node_modules/lodash.pad/index.js 3327909: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_readable.js 67593383: node_modules/lodash._baseslice/index.js 67593383: node_modules/lodash._baseslice/index.js 67646936: node_modules/lodash.tostring/index.js 67646936: node_modules/lodash.tostring/index.js 56978227: node_modules/falafel/node_modules/isarray/index.js 56174974: node_modules/core-util-is/lib/util.js 67615561: node_modules/lodash.padend/index.js 67615561: node_modules/lodash.padend/index.js 3357009: node_modules/babel-core/node_modules/regenerator/node_modules/commoner/node_modules/glob/node_modules/inherits/inherits.js 3357051: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_writable.js 67631576: node_modules/lodash.padstart/index.js 67631576: node_modules/lodash.padstart/index.js 3370120: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_duplex.js 3372931: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_transform.js 3380281: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_passthrough.js 56223160: node_modules/delegates/index.js 57167856: node_modules/gauge/progress-bar.js 3382008: node_modules/node-pre-gyp/lib/pre-binding.js 3382008: node_modules/node-pre-gyp/lib/pre-binding.js 3382833: node_modules/node-pre-gyp/lib/util/versioning.js 57204450: node_modules/has-unicode/index.js 3382833: node_modules/node-pre-gyp/lib/util/versioning.js 41738129: node_modules/ansi/lib/ansi.js 3396883: node_modules/node-pre-gyp/node_modules/semver/semver.js 3396883: node_modules/node-pre-gyp/node_modules/semver/semver.js 41746103: node_modules/ansi/lib/newlines.js 67599487: node_modules/lodash.pad/index.js 67593383: node_modules/lodash._baseslice/index.js 3429402: node_modules/node-pre-gyp/lib/util/abi_crosswalk.json 67646936: node_modules/lodash.tostring/index.js 3429402: node_modules/node-pre-gyp/lib/util/abi_crosswalk.json 3446169: node_modules/node-pre-gyp/package.json 67615561: node_modules/lodash.padend/index.js 3446169: node_modules/node-pre-gyp/package.json 3305440: node_modules/sqlite3/package.json 67631576: node_modules/lodash.padstart/index.js 3305440: node_modules/sqlite3/package.json 3382008: node_modules/node-pre-gyp/lib/pre-binding.js 3382833: node_modules/node-pre-gyp/lib/util/versioning.js 3396883: node_modules/node-pre-gyp/node_modules/semver/semver.js 3449351: src/flux/models/model.js 3449351: src/flux/models/model.js 3454751: src/flux/attributes.js 3454751: src/flux/attributes.js 3458403: src/flux/attributes/matcher.js 3458403: src/flux/attributes/matcher.js 3429402: node_modules/node-pre-gyp/lib/util/abi_crosswalk.json 3446169: node_modules/node-pre-gyp/package.json 3305440: node_modules/sqlite3/package.json 3470821: src/flux/attributes/sort-order.js 3470821: src/flux/attributes/sort-order.js 3471723: src/flux/attributes/attribute.js 3471723: src/flux/attributes/attribute.js 3474483: src/flux/attributes/attribute-number.js 3474483: src/flux/attributes/attribute-number.js 3477709: src/flux/attributes/attribute-string.js 3477709: src/flux/attributes/attribute-string.js 3479579: src/flux/attributes/attribute-object.js 3479579: src/flux/attributes/attribute-object.js 3481139: src/flux/attributes/attribute-boolean.js 3481139: src/flux/attributes/attribute-boolean.js 3482541: src/flux/attributes/attribute-datetime.js 3482541: src/flux/attributes/attribute-datetime.js 3485716: src/flux/attributes/attribute-collection.js 3485716: src/flux/attributes/attribute-collection.js 3490067: src/flux/attributes/attribute-joined-data.js 3490067: src/flux/attributes/attribute-joined-data.js 3492659: src/flux/attributes/attribute-serverid.js 3492659: src/flux/attributes/attribute-serverid.js 3494243: src/flux/actions.js 3449351: src/flux/models/model.js 3494243: src/flux/actions.js 3509768: node_modules/reflux/package.json 3454751: src/flux/attributes.js 3509768: node_modules/reflux/package.json 3511690: node_modules/reflux/src/index.js 3458403: src/flux/attributes/matcher.js 3511690: node_modules/reflux/src/index.js 3513193: node_modules/reflux/src/ListenerMethods.js 3513193: node_modules/reflux/src/ListenerMethods.js 3519984: node_modules/reflux/src/utils.js 3519984: node_modules/reflux/src/utils.js 3521383: node_modules/reflux/node_modules/eventemitter3/index.js 3521383: node_modules/reflux/node_modules/eventemitter3/index.js 3470821: src/flux/attributes/sort-order.js 3527461: node_modules/reflux/src/joins.js 3471723: src/flux/attributes/attribute.js 3527461: node_modules/reflux/src/joins.js 3530350: node_modules/reflux/src/createStore.js 3530350: node_modules/reflux/src/createStore.js 3474483: src/flux/attributes/attribute-number.js 3531848: node_modules/reflux/src/Keep.js 3477709: src/flux/attributes/attribute-string.js 3531848: node_modules/reflux/src/Keep.js 3479579: src/flux/attributes/attribute-object.js 3532111: node_modules/reflux/src/PublisherMethods.js 3532111: node_modules/reflux/src/PublisherMethods.js 3481139: src/flux/attributes/attribute-boolean.js 3534287: node_modules/reflux/src/createAction.js 3534287: node_modules/reflux/src/createAction.js 3482541: src/flux/attributes/attribute-datetime.js 3535424: node_modules/reflux/src/connect.js 3535424: node_modules/reflux/src/connect.js 3485716: src/flux/attributes/attribute-collection.js 3536186: node_modules/reflux/src/ListenerMixin.js 3536186: node_modules/reflux/src/ListenerMixin.js 3490067: src/flux/attributes/attribute-joined-data.js 3536620: node_modules/reflux/src/listenTo.js 3536620: node_modules/reflux/src/listenTo.js 3538124: node_modules/reflux/src/listenToMany.js 3492659: src/flux/attributes/attribute-serverid.js 3538124: node_modules/reflux/src/listenToMany.js 3494243: src/flux/actions.js 3509768: node_modules/reflux/package.json 3511690: node_modules/reflux/src/index.js 3513193: node_modules/reflux/src/ListenerMethods.js 3519984: node_modules/reflux/src/utils.js 3521383: node_modules/reflux/node_modules/eventemitter3/index.js 3527461: node_modules/reflux/src/joins.js 3530350: node_modules/reflux/src/createStore.js 3531848: node_modules/reflux/src/Keep.js 3532111: node_modules/reflux/src/PublisherMethods.js 3534287: node_modules/reflux/src/createAction.js 3535424: node_modules/reflux/src/connect.js 3539478: src/flux/models/query.js 3539478: src/flux/models/query.js 3536186: node_modules/reflux/src/ListenerMixin.js 3536620: node_modules/reflux/src/listenTo.js 3538124: node_modules/reflux/src/listenToMany.js 3553781: src/flux/models/query-range.js 3553781: src/flux/models/query-range.js 3556781: src/global/nylas-store.js 3556781: src/global/nylas-store.js 3557281: src/flux/modules/reflux-coffee.js 3557281: src/flux/modules/reflux-coffee.js 3564303: node_modules/underscore.string/package.json 3564303: node_modules/underscore.string/package.json 3126085: node_modules/underscore.string/index.js 3126085: node_modules/underscore.string/index.js 3130619: node_modules/underscore.string/isBlank.js 3130619: node_modules/underscore.string/isBlank.js 3130755: node_modules/underscore.string/helper/makeString.js 3130755: node_modules/underscore.string/helper/makeString.js 3130916: node_modules/underscore.string/stripTags.js 3130916: node_modules/underscore.string/stripTags.js 3131065: node_modules/underscore.string/capitalize.js 3131065: node_modules/underscore.string/capitalize.js 3131341: node_modules/underscore.string/decapitalize.js 3131341: node_modules/underscore.string/decapitalize.js 3131518: node_modules/underscore.string/chop.js 3131518: node_modules/underscore.string/chop.js 3131710: node_modules/underscore.string/trim.js 3131710: node_modules/underscore.string/trim.js 3132143: node_modules/underscore.string/helper/defaultToWhiteSpace.js 3132143: node_modules/underscore.string/helper/defaultToWhiteSpace.js 3132413: node_modules/underscore.string/helper/escapeRegExp.js 3132413: node_modules/underscore.string/helper/escapeRegExp.js 3132577: node_modules/underscore.string/clean.js 3132577: node_modules/underscore.string/clean.js 3132693: node_modules/underscore.string/cleanDiacritics.js 3132693: node_modules/underscore.string/cleanDiacritics.js 3133280: node_modules/underscore.string/count.js 3133280: node_modules/underscore.string/count.js 3133530: node_modules/underscore.string/chars.js 3133530: node_modules/underscore.string/chars.js 3539478: src/flux/models/query.js 3133658: node_modules/underscore.string/swapCase.js 3133883: node_modules/underscore.string/escapeHTML.js 3133658: node_modules/underscore.string/swapCase.js 3134273: node_modules/underscore.string/helper/escapeChars.js 3133883: node_modules/underscore.string/escapeHTML.js 3134692: node_modules/underscore.string/unescapeHTML.js 3553781: src/flux/models/query-range.js 3134273: node_modules/underscore.string/helper/escapeChars.js 3135351: node_modules/underscore.string/helper/htmlEntities.js 3134692: node_modules/underscore.string/unescapeHTML.js 3135655: node_modules/underscore.string/splice.js 3135351: node_modules/underscore.string/helper/htmlEntities.js 3556781: src/global/nylas-store.js 3135836: node_modules/underscore.string/insert.js 3135655: node_modules/underscore.string/splice.js 3135961: node_modules/underscore.string/replaceAll.js 3135836: node_modules/underscore.string/insert.js 3136217: node_modules/underscore.string/include.js 3557281: src/flux/modules/reflux-coffee.js 3135961: node_modules/underscore.string/replaceAll.js 3136402: node_modules/underscore.string/join.js 3136217: node_modules/underscore.string/include.js 3136622: node_modules/underscore.string/lines.js 3136402: node_modules/underscore.string/join.js 3136734: node_modules/underscore.string/dedent.js 3136622: node_modules/underscore.string/lines.js 3136734: node_modules/underscore.string/dedent.js 3564303: node_modules/underscore.string/package.json 3137344: node_modules/underscore.string/reverse.js 3126085: node_modules/underscore.string/index.js 3137461: node_modules/underscore.string/startsWith.js 3137811: node_modules/underscore.string/helper/toPositive.js 3130619: node_modules/underscore.string/isBlank.js 3137903: node_modules/underscore.string/endsWith.js 3130755: node_modules/underscore.string/helper/makeString.js 3137344: node_modules/underscore.string/reverse.js 3138345: node_modules/underscore.string/pred.js 3130916: node_modules/underscore.string/stripTags.js 3138460: node_modules/underscore.string/helper/adjacent.js 3137461: node_modules/underscore.string/startsWith.js 3131065: node_modules/underscore.string/capitalize.js 3137811: node_modules/underscore.string/helper/toPositive.js 3131341: node_modules/underscore.string/decapitalize.js 3138722: node_modules/underscore.string/succ.js 3137903: node_modules/underscore.string/endsWith.js 3131518: node_modules/underscore.string/chop.js 3138836: node_modules/underscore.string/titleize.js 3131710: node_modules/underscore.string/trim.js 3138345: node_modules/underscore.string/pred.js 3139043: node_modules/underscore.string/camelize.js 3132143: node_modules/underscore.string/helper/defaultToWhiteSpace.js 3138460: node_modules/underscore.string/helper/adjacent.js 3139364: node_modules/underscore.string/underscored.js 3132413: node_modules/underscore.string/helper/escapeRegExp.js 3139540: node_modules/underscore.string/dasherize.js 3132577: node_modules/underscore.string/clean.js 3139703: node_modules/underscore.string/classify.js 3132693: node_modules/underscore.string/cleanDiacritics.js 3139981: node_modules/underscore.string/humanize.js 3138722: node_modules/underscore.string/succ.js 3140227: node_modules/underscore.string/ltrim.js 3138836: node_modules/underscore.string/titleize.js 3140651: node_modules/underscore.string/rtrim.js 3133280: node_modules/underscore.string/count.js 3139043: node_modules/underscore.string/camelize.js 3141074: node_modules/underscore.string/truncate.js 3133530: node_modules/underscore.string/chars.js 3141347: node_modules/underscore.string/prune.js 3139364: node_modules/underscore.string/underscored.js 3133658: node_modules/underscore.string/swapCase.js 3139540: node_modules/underscore.string/dasherize.js 3142255: node_modules/underscore.string/words.js 3139703: node_modules/underscore.string/classify.js 3142463: node_modules/underscore.string/pad.js 3133883: node_modules/underscore.string/escapeHTML.js 3139981: node_modules/underscore.string/humanize.js 3143150: node_modules/underscore.string/helper/strRepeat.js 3134273: node_modules/underscore.string/helper/escapeChars.js 3143345: node_modules/underscore.string/lpad.js 3140227: node_modules/underscore.string/ltrim.js 3143466: node_modules/underscore.string/rpad.js 3134692: node_modules/underscore.string/unescapeHTML.js 3140651: node_modules/underscore.string/rtrim.js 3143596: node_modules/underscore.string/lrpad.js 3135351: node_modules/underscore.string/helper/htmlEntities.js 3141074: node_modules/underscore.string/truncate.js 3135655: node_modules/underscore.string/splice.js 3141347: node_modules/underscore.string/prune.js 3143726: node_modules/underscore.string/sprintf.js 3135836: node_modules/underscore.string/insert.js 4476299: node_modules/juice/node_modules/util-deprecate/node.js 3142255: node_modules/underscore.string/words.js 3135961: node_modules/underscore.string/replaceAll.js 3142463: node_modules/underscore.string/pad.js 89722232: node_modules/underscore.string/node_modules/sprintf-js/src/sprintf.js 3136217: node_modules/underscore.string/include.js 3143150: node_modules/underscore.string/helper/strRepeat.js 3136402: node_modules/underscore.string/join.js 3143345: node_modules/underscore.string/lpad.js 3136622: node_modules/underscore.string/lines.js 3143466: node_modules/underscore.string/rpad.js 3136734: node_modules/underscore.string/dedent.js 3143923: node_modules/underscore.string/vsprintf.js 3143596: node_modules/underscore.string/lrpad.js 3137344: node_modules/underscore.string/reverse.js 3144122: node_modules/underscore.string/toNumber.js 3143726: node_modules/underscore.string/sprintf.js 3137461: node_modules/underscore.string/startsWith.js 3144317: node_modules/underscore.string/numberFormat.js 4476299: node_modules/juice/node_modules/util-deprecate/node.js 3137811: node_modules/underscore.string/helper/toPositive.js 3144704: node_modules/underscore.string/strRight.js 3137903: node_modules/underscore.string/endsWith.js 3144959: node_modules/underscore.string/strRightBack.js 89722232: node_modules/underscore.string/node_modules/sprintf-js/src/sprintf.js 3138345: node_modules/underscore.string/pred.js 3145222: node_modules/underscore.string/strLeft.js 3138460: node_modules/underscore.string/helper/adjacent.js 3145454: node_modules/underscore.string/strLeftBack.js 3145682: node_modules/underscore.string/toSentence.js 3143923: node_modules/underscore.string/vsprintf.js 3138722: node_modules/underscore.string/succ.js 3146093: node_modules/underscore.string/toSentenceSerial.js 3144122: node_modules/underscore.string/toNumber.js 3144317: node_modules/underscore.string/numberFormat.js 3138836: node_modules/underscore.string/titleize.js 3146253: node_modules/underscore.string/slugify.js 3144704: node_modules/underscore.string/strRight.js 3139043: node_modules/underscore.string/camelize.js 3146513: node_modules/underscore.string/surround.js 3144959: node_modules/underscore.string/strRightBack.js 3139364: node_modules/underscore.string/underscored.js 3146610: node_modules/underscore.string/quote.js 3145222: node_modules/underscore.string/strLeft.js 3139540: node_modules/underscore.string/dasherize.js 3146744: node_modules/underscore.string/unquote.js 3145454: node_modules/underscore.string/strLeftBack.js 3139703: node_modules/underscore.string/classify.js 3146956: node_modules/underscore.string/repeat.js 3145682: node_modules/underscore.string/toSentence.js 3147436: node_modules/underscore.string/naturalCmp.js 3139981: node_modules/underscore.string/humanize.js 3146093: node_modules/underscore.string/toSentenceSerial.js 3148137: node_modules/underscore.string/levenshtein.js 3140227: node_modules/underscore.string/ltrim.js 3140651: node_modules/underscore.string/rtrim.js 3149427: node_modules/underscore.string/toBoolean.js 3146253: node_modules/underscore.string/slugify.js 3150095: node_modules/underscore.string/exports.js 3141074: node_modules/underscore.string/truncate.js 3150336: node_modules/underscore.string/wrap.js 3146513: node_modules/underscore.string/surround.js 3141347: node_modules/underscore.string/prune.js 3146610: node_modules/underscore.string/quote.js 3152857: node_modules/underscore.string/map.js 3142255: node_modules/underscore.string/words.js 3146744: node_modules/underscore.string/unquote.js 3142463: node_modules/underscore.string/pad.js 3146956: node_modules/underscore.string/repeat.js 3143150: node_modules/underscore.string/helper/strRepeat.js 3147436: node_modules/underscore.string/naturalCmp.js 3143345: node_modules/underscore.string/lpad.js 3148137: node_modules/underscore.string/levenshtein.js 3568295: src/flux/coffee-helpers.js 3143466: node_modules/underscore.string/rpad.js 3149427: node_modules/underscore.string/toBoolean.js 3143596: node_modules/underscore.string/lrpad.js 3150095: node_modules/underscore.string/exports.js 3143726: node_modules/underscore.string/sprintf.js 3150336: node_modules/underscore.string/wrap.js 4476299: node_modules/juice/node_modules/util-deprecate/node.js 3152857: node_modules/underscore.string/map.js 3570836: node_modules/promise-queue/package.json 89722232: node_modules/underscore.string/node_modules/sprintf-js/src/sprintf.js 3572457: node_modules/promise-queue/index.js 3568295: src/flux/coffee-helpers.js 3572560: node_modules/promise-queue/lib/index.js 3143923: node_modules/underscore.string/vsprintf.js 3144122: node_modules/underscore.string/toNumber.js 3144317: node_modules/underscore.string/numberFormat.js 3577195: src/priority-ui-coordinator.js 3144704: node_modules/underscore.string/strRight.js 3144959: node_modules/underscore.string/strRightBack.js 3570836: node_modules/promise-queue/package.json 3145222: node_modules/underscore.string/strLeft.js 3579245: src/flux/stores/database-setup-query-builder.js 3572457: node_modules/promise-queue/index.js 3145454: node_modules/underscore.string/strLeftBack.js 3145682: node_modules/underscore.string/toSentence.js 3583641: src/flux/stores/database-change-record.js 3572560: node_modules/promise-queue/lib/index.js 3146093: node_modules/underscore.string/toSentenceSerial.js 3585323: src/flux/stores/database-writer.js 3146253: node_modules/underscore.string/slugify.js 3577195: src/priority-ui-coordinator.js 3146513: node_modules/underscore.string/surround.js 3146610: node_modules/underscore.string/quote.js 3146744: node_modules/underscore.string/unquote.js 3146956: node_modules/underscore.string/repeat.js 3579245: src/flux/stores/database-setup-query-builder.js 3147436: node_modules/underscore.string/naturalCmp.js 3148137: node_modules/underscore.string/levenshtein.js 3583641: src/flux/stores/database-change-record.js 3149427: node_modules/underscore.string/toBoolean.js 3150095: node_modules/underscore.string/exports.js 3585323: src/flux/stores/database-writer.js 3150336: node_modules/underscore.string/wrap.js 3152857: node_modules/underscore.string/map.js 3568295: src/flux/coffee-helpers.js 3599638: src/apm-wrapper.js 3570836: node_modules/promise-queue/package.json 3572457: node_modules/promise-queue/index.js 3613961: src/buffered-process.js 3572560: node_modules/promise-queue/lib/index.js 3577195: src/priority-ui-coordinator.js 3599638: src/apm-wrapper.js 3621867: src/clipboard.js 3579245: src/flux/stores/database-setup-query-builder.js 3583641: src/flux/stores/database-change-record.js 3613961: src/buffered-process.js 3622937: src/theme-manager.js 3585323: src/flux/stores/database-writer.js 3621867: src/clipboard.js 3642517: src/style-manager.js 3648228: src/flux/action-bridge.js 3622937: src/theme-manager.js 3654791: src/menu-manager.js 3658911: src/menu-helpers.js 3642517: src/style-manager.js 3648228: src/flux/action-bridge.js 3599638: src/apm-wrapper.js 3654791: src/menu-manager.js 3658911: src/menu-helpers.js 3613961: src/buffered-process.js 3621867: src/clipboard.js 3622937: src/theme-manager.js 3677020: menus/darwin.json 3642517: src/style-manager.js 3648228: src/flux/action-bridge.js 3654791: src/menu-manager.js 3677020: menus/darwin.json 3662409: src/nylas-spellchecker.js 3658911: src/menu-helpers.js 3662409: src/nylas-spellchecker.js 3677020: menus/darwin.json 3662409: src/nylas-spellchecker.js 3798011: src/global/nylas-exports.js 3798011: src/global/nylas-exports.js 5912469: src/deprecate-utils.js 3668481: src/config-schema.js 5912469: src/deprecate-utils.js 3798011: src/global/nylas-exports.js 5912469: src/deprecate-utils.js 3668481: src/config-schema.js 4687050: src/global/nylas-observables.js 4697858: node_modules/rx-lite/package.json 4699647: node_modules/rx-lite/rx.lite.js 4687050: src/global/nylas-observables.js 4697858: node_modules/rx-lite/package.json 4699647: node_modules/rx-lite/rx.lite.js 4699647: node_modules/rx-lite/rx.lite.js 4687050: src/global/nylas-observables.js 4699647: node_modules/rx-lite/rx.lite.js 4687050: src/global/nylas-observables.js 3925280: src/flux/models/category.js 5180618: src/flux/models/query-subscription-pool.js 5195386: src/flux/models/query-subscription.js 5231737: src/flux/models/mutable-query-result-set.js 5237299: src/flux/models/query-result-set.js 5389575: src/flux/stores/task-queue.js 3925280: src/flux/models/category.js 5180618: src/flux/models/query-subscription-pool.js 3813280: src/flux/tasks/task.js 5195386: src/flux/models/query-subscription.js 5231737: src/flux/models/mutable-query-result-set.js 4200026: src/flux/nylas-api.js 5237299: src/flux/models/query-result-set.js 5389575: src/flux/stores/task-queue.js 4222287: node_modules/request/package.json 4225420: node_modules/request/index.js 80787899: node_modules/request/node_modules/extend/index.js 4229450: node_modules/request/lib/cookies.js 4230419: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/cookie.js 3813280: src/flux/tasks/task.js 4267962: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js 4200026: src/flux/nylas-api.js 4222287: node_modules/request/package.json 4225420: node_modules/request/index.js 80787899: node_modules/request/node_modules/extend/index.js 4229450: node_modules/request/lib/cookies.js 4230419: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/cookie.js 4267962: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js 4417589: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/store.js 4420430: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/memstore.js 4425944: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/permuteDomain.js 4428210: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pathMatch.js 4430645: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/package.json 4432858: node_modules/request/lib/helpers.js 4434482: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/json-stringify-safe/stringify.js 4435389: node_modules/request/request.js 4417589: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/store.js 80567623: node_modules/request/node_modules/bl/bl.js 4420430: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/memstore.js 4425944: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/permuteDomain.js 80636139: node_modules/request/node_modules/bl/node_modules/readable-stream/duplex.js 4428210: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pathMatch.js 80636191: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_duplex.js 4430645: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/package.json 75226954: node_modules/process-nextick-args/index.js 80638643: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_readable.js 4432858: node_modules/request/lib/helpers.js 4434482: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/json-stringify-safe/stringify.js 4435389: node_modules/request/request.js 57417682: node_modules/isarray/index.js 80670635: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_writable.js 81345592: node_modules/request/node_modules/hawk/lib/index.js 80567623: node_modules/request/node_modules/bl/bl.js 81416906: node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js 80636139: node_modules/request/node_modules/bl/node_modules/readable-stream/duplex.js 80636191: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_duplex.js 75226954: node_modules/process-nextick-args/index.js 80638643: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_readable.js 81490930: node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js 57417682: node_modules/isarray/index.js 80670635: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_writable.js 81488262: node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js 81520773: node_modules/request/node_modules/hawk/node_modules/sntp/index.js 81345592: node_modules/request/node_modules/hawk/lib/index.js 81416906: node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js 81520807: node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js 81345973: node_modules/request/node_modules/hawk/lib/server.js 81490930: node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js 81488262: node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js 81520773: node_modules/request/node_modules/hawk/node_modules/sntp/index.js 81520807: node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js 81428267: node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js 81342006: node_modules/request/node_modules/hawk/lib/crypto.js 81364519: node_modules/request/node_modules/hawk/lib/utils.js 81331415: node_modules/request/node_modules/hawk/lib/client.js 80480692: node_modules/request/node_modules/aws-sign2/index.js 81551606: node_modules/request/node_modules/http-signature/lib/index.js 81552232: node_modules/request/node_modules/http-signature/lib/parser.js 81585919: node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js 81345973: node_modules/request/node_modules/hawk/lib/server.js 81428267: node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js 81342006: node_modules/request/node_modules/hawk/lib/crypto.js 81574938: node_modules/request/node_modules/http-signature/lib/utils.js 81364519: node_modules/request/node_modules/hawk/lib/utils.js 81887698: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/index.js 81888429: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/key.js 81331415: node_modules/request/node_modules/hawk/lib/client.js 81950012: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/assert.js 80480692: node_modules/request/node_modules/aws-sign2/index.js 81551606: node_modules/request/node_modules/http-signature/lib/index.js 81552232: node_modules/request/node_modules/http-signature/lib/parser.js 81585919: node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js 81830178: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/algs.js 81847974: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/fingerprint.js 81574938: node_modules/request/node_modules/http-signature/lib/utils.js 81845672: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/errors.js 81911179: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/utils.js 81887698: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/index.js 81888429: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/key.js 81895828: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/private-key.js 81950012: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/assert.js 81901963: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/signature.js 81942773: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/index.js 81928490: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/index.js 81830178: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/algs.js 81928251: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/errors.js 81934548: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/types.js 81847974: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/fingerprint.js 81845672: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/errors.js 81928959: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/reader.js 81911179: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/utils.js 81935186: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js 81895828: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/private-key.js 81901963: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/signature.js 81908010: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ssh-buffer.js 81942773: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/index.js 81843337: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ed-compat.js 81928490: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/index.js 81928251: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/errors.js 81851404: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/auto.js 81934548: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/types.js 81853302: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pem.js 81858111: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs1.js 81928959: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/reader.js 81865807: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs8.js 81935186: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js 81881346: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh-private.js 81877740: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/rfc4253.js 81908010: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ssh-buffer.js 81843337: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ed-compat.js 81884606: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh.js 81851404: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/auto.js 81835020: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/dhe.js 81853302: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pem.js 81858111: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs1.js 81562004: node_modules/request/node_modules/http-signature/lib/signer.js 81865807: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs8.js 81602307: node_modules/request/node_modules/http-signature/node_modules/jsprim/lib/jsprim.js 81881346: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh-private.js 81632804: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/lib/extsprintf.js 81877740: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/rfc4253.js 81797823: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/lib/verror.js 81763963: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/lib/validate.js 81884606: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh.js 81835020: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/dhe.js 81577777: node_modules/request/node_modules/http-signature/lib/verify.js 82371286: node_modules/request/node_modules/mime-types/index.js 81562004: node_modules/request/node_modules/http-signature/lib/signer.js 82530510: node_modules/request/node_modules/mime-types/node_modules/mime-db/index.js 82387545: node_modules/request/node_modules/mime-types/node_modules/mime-db/db.json 81602307: node_modules/request/node_modules/http-signature/node_modules/jsprim/lib/jsprim.js 81632804: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/lib/extsprintf.js 81797823: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/lib/verror.js 81763963: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/lib/validate.js 81577777: node_modules/request/node_modules/http-signature/lib/verify.js 82371286: node_modules/request/node_modules/mime-types/index.js 82530510: node_modules/request/node_modules/mime-types/node_modules/mime-db/index.js 82387545: node_modules/request/node_modules/mime-types/node_modules/mime-db/db.json 4476422: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/stringstream/stringstream.js 80754327: node_modules/request/node_modules/caseless/index.js 80801324: node_modules/request/node_modules/forever-agent/index.js 80814876: node_modules/request/node_modules/form-data/lib/form_data.js 3668481: src/config-schema.js 80764215: node_modules/request/node_modules/combined-stream/lib/combined_stream.js 80773528: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js 80944514: node_modules/request/node_modules/form-data/node_modules/async/lib/async.js 4476422: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/stringstream/stringstream.js 80754327: node_modules/request/node_modules/caseless/index.js 80801324: node_modules/request/node_modules/forever-agent/index.js 80814876: node_modules/request/node_modules/form-data/lib/form_data.js 80826033: node_modules/request/node_modules/form-data/lib/populate.js 82348558: node_modules/request/node_modules/isstream/isstream.js 82341499: node_modules/request/node_modules/is-typedarray/index.js 80764215: node_modules/request/node_modules/combined-stream/lib/combined_stream.js 4479214: node_modules/request/lib/getProxyFromURI.js 4481482: node_modules/request/lib/querystring.js 80773528: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js 82587962: node_modules/request/node_modules/qs/lib/index.js 82593363: node_modules/request/node_modules/qs/lib/stringify.js 82597342: node_modules/request/node_modules/qs/lib/utils.js 80944514: node_modules/request/node_modules/form-data/node_modules/async/lib/async.js 82588115: node_modules/request/node_modules/qs/lib/parse.js 4482815: node_modules/request/lib/har.js 81001381: node_modules/request/node_modules/har-validator/lib/index.js 81163939: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/index.js 81001935: node_modules/request/node_modules/har-validator/lib/runner.js 80826033: node_modules/request/node_modules/form-data/lib/populate.js 81005359: node_modules/request/node_modules/har-validator/lib/schemas/index.js 81002525: node_modules/request/node_modules/har-validator/lib/schemas/cache.json 82348558: node_modules/request/node_modules/isstream/isstream.js 81002712: node_modules/request/node_modules/har-validator/lib/schemas/cacheEntry.json 81003206: node_modules/request/node_modules/har-validator/lib/schemas/content.json 82341499: node_modules/request/node_modules/is-typedarray/index.js 81003583: node_modules/request/node_modules/har-validator/lib/schemas/cookie.json 81004081: node_modules/request/node_modules/har-validator/lib/schemas/creator.json 4479214: node_modules/request/lib/getProxyFromURI.js 81004311: node_modules/request/node_modules/har-validator/lib/schemas/entry.json 81005242: node_modules/request/node_modules/har-validator/lib/schemas/har.json 4481482: node_modules/request/lib/querystring.js 81007111: node_modules/request/node_modules/har-validator/lib/schemas/log.json 81007604: node_modules/request/node_modules/har-validator/lib/schemas/page.json 82587962: node_modules/request/node_modules/qs/lib/index.js 81008181: node_modules/request/node_modules/har-validator/lib/schemas/pageTimings.json 81008406: node_modules/request/node_modules/har-validator/lib/schemas/postData.json 82593363: node_modules/request/node_modules/qs/lib/stringify.js 81009060: node_modules/request/node_modules/har-validator/lib/schemas/record.json 81009286: node_modules/request/node_modules/har-validator/lib/schemas/request.json 81010139: node_modules/request/node_modules/har-validator/lib/schemas/response.json 82597342: node_modules/request/node_modules/qs/lib/utils.js 81010946: node_modules/request/node_modules/har-validator/lib/schemas/timings.json 81001195: node_modules/request/node_modules/har-validator/lib/error.js 81108729: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/index.js 82588115: node_modules/request/node_modules/qs/lib/parse.js 81132607: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/index.js 4482815: node_modules/request/lib/har.js 81134601: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/is-property.js 81001381: node_modules/request/node_modules/har-validator/lib/index.js 81127606: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/index.js 81163939: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/index.js 81149530: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/jsonpointer.js 81001935: node_modules/request/node_modules/har-validator/lib/runner.js 4525735: node_modules/babel-core/node_modules/output-file-sync/node_modules/xtend/immutable.js 81106380: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/formats.js 81005359: node_modules/request/node_modules/har-validator/lib/schemas/index.js 81002525: node_modules/request/node_modules/har-validator/lib/schemas/cache.json 81002712: node_modules/request/node_modules/har-validator/lib/schemas/cacheEntry.json 4533728: node_modules/request/lib/auth.js 81003206: node_modules/request/node_modules/har-validator/lib/schemas/content.json 81003583: node_modules/request/node_modules/har-validator/lib/schemas/cookie.json 81004081: node_modules/request/node_modules/har-validator/lib/schemas/creator.json 81004311: node_modules/request/node_modules/har-validator/lib/schemas/entry.json 81005242: node_modules/request/node_modules/har-validator/lib/schemas/har.json 81007111: node_modules/request/node_modules/har-validator/lib/schemas/log.json 4550226: node_modules/request/lib/oauth.js 81007604: node_modules/request/node_modules/har-validator/lib/schemas/page.json 81008181: node_modules/request/node_modules/har-validator/lib/schemas/pageTimings.json 81008406: node_modules/request/node_modules/har-validator/lib/schemas/postData.json 81009060: node_modules/request/node_modules/har-validator/lib/schemas/record.json 81009286: node_modules/request/node_modules/har-validator/lib/schemas/request.json 82544802: node_modules/request/node_modules/oauth-sign/index.js 81010139: node_modules/request/node_modules/har-validator/lib/schemas/response.json 81010946: node_modules/request/node_modules/har-validator/lib/schemas/timings.json 81001195: node_modules/request/node_modules/har-validator/lib/error.js 4568756: node_modules/request/lib/multipart.js 81108729: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/index.js 4585628: node_modules/request/lib/redirect.js 4594531: node_modules/request/lib/tunnel.js 81132607: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/index.js 4601413: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tunnel-agent/index.js 81134601: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/is-property.js 81127606: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/index.js 81149530: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/jsonpointer.js 91866084: src/flux/nylas-long-connection.js 4525735: node_modules/babel-core/node_modules/output-file-sync/node_modules/xtend/immutable.js 81106380: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/formats.js 2376215: node_modules/event-kit/package.json 4533728: node_modules/request/lib/auth.js 3905749: src/flux/models/account.js 3911874: src/flux/models/model-with-metadata.js 4550226: node_modules/request/lib/oauth.js 82544802: node_modules/request/node_modules/oauth-sign/index.js 4568756: node_modules/request/lib/multipart.js 4585628: node_modules/request/lib/redirect.js 3959955: src/flux/models/message.js 4594531: node_modules/request/lib/tunnel.js 3971136: node_modules/moment/package.json 4601413: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tunnel-agent/index.js 3809622: src/flux/models/file.js 91866084: src/flux/nylas-long-connection.js 3870842: src/flux/models/event.js 3875483: src/flux/models/contact.js 2376215: node_modules/event-kit/package.json 3886010: src/regexp-utils.js 3905749: src/flux/models/account.js 56664169: node_modules/emoji-data/lib/emoji_data.js 3911874: src/flux/models/model-with-metadata.js 56662240: node_modules/emoji-data/lib/emoji_char.js 56691400: node_modules/emoji-data/node_modules/underscore.string/lib/underscore.string.js 3959955: src/flux/models/message.js 3971136: node_modules/moment/package.json 3809622: src/flux/models/file.js 3870842: src/flux/models/event.js 3875483: src/flux/models/contact.js 3886010: src/regexp-utils.js 56664169: node_modules/emoji-data/lib/emoji_data.js 56662240: node_modules/emoji-data/lib/emoji_char.js 56691400: node_modules/emoji-data/node_modules/underscore.string/lib/underscore.string.js 3889367: src/flux/stores/account-store.js 65006241: node_modules/keytar/package.json 65004180: node_modules/keytar/lib/keytar.js 3889367: src/flux/stores/account-store.js 65006241: node_modules/keytar/package.json 65004180: node_modules/keytar/lib/keytar.js 4687050: src/global/nylas-observables.js 4697858: node_modules/rx-lite/package.json 3925080: src/flux/models/label.js 4699647: node_modules/rx-lite/rx.lite.js 3930438: src/flux/models/folder.js 3930638: src/flux/models/thread.js 4096909: src/flux/models/calendar.js 4098495: src/flux/models/json-blob.js 3925080: src/flux/models/label.js 3930438: src/flux/models/folder.js 3930638: src/flux/models/thread.js 4096909: src/flux/models/calendar.js 5951047: src/flux/stores/badge-store.js 5726955: src/flux/stores/focused-perspective-store.js 5744701: src/flux/stores/workspace-store.js 5951047: src/flux/stores/badge-store.js 5726955: src/flux/stores/focused-perspective-store.js 4648657: src/flux/stores/category-store.js 5744701: src/flux/stores/workspace-store.js 9942964: src/flux/stores/nylas-sync-status-store.js 4648657: src/flux/stores/category-store.js 9942964: src/flux/stores/nylas-sync-status-store.js 4699647: node_modules/rx-lite/rx.lite.js 4098495: src/flux/models/json-blob.js 4687050: src/global/nylas-observables.js 4100089: src/mailbox-perspective.js 3925280: src/flux/models/category.js 4120446: src/flux/tasks/task-factory.js 4139229: src/flux/tasks/change-folder-task.js 5180618: src/flux/models/query-subscription-pool.js 4156736: src/flux/tasks/change-mail-task.js 5195386: src/flux/models/query-subscription.js 4100089: src/mailbox-perspective.js 5231737: src/flux/models/mutable-query-result-set.js 4120446: src/flux/tasks/task-factory.js 4636283: src/flux/tasks/syncback-category-task.js 5237299: src/flux/models/query-result-set.js 4139229: src/flux/tasks/change-folder-task.js 5389575: src/flux/stores/task-queue.js 5273907: src/flux/tasks/change-labels-task.js 4156736: src/flux/tasks/change-mail-task.js 5304677: src/flux/tasks/change-unread-task.js 3813280: src/flux/tasks/task.js 4636283: src/flux/tasks/syncback-category-task.js 5341333: src/flux/tasks/change-starred-task.js 4200026: src/flux/nylas-api.js 5350052: src/flux/stores/outbox-store.js 5356198: src/flux/tasks/send-draft-task.js 5273907: src/flux/tasks/change-labels-task.js 5417961: src/sound-registry.js 91943581: src/flux/tasks/base-draft-task.js 4222287: node_modules/request/package.json 5304677: src/flux/tasks/change-unread-task.js 4225420: node_modules/request/index.js 5419733: src/flux/tasks/syncback-metadata-task.js 80787899: node_modules/request/node_modules/extend/index.js 4229450: node_modules/request/lib/cookies.js 5431422: src/flux/tasks/syncback-model-task.js 5341333: src/flux/tasks/change-starred-task.js 4230419: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/cookie.js 91991403: src/flux/tasks/notify-plugins-of-send-task.js 5350052: src/flux/stores/outbox-store.js 5356198: src/flux/tasks/send-draft-task.js 4267962: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js 91821594: src/flux/edgehill-api.js 5417961: src/sound-registry.js 91943581: src/flux/tasks/base-draft-task.js 5471010: src/flux/stores/task-queue-status-store.js 5419733: src/flux/tasks/syncback-metadata-task.js 5431422: src/flux/tasks/syncback-model-task.js 91991403: src/flux/tasks/notify-plugins-of-send-task.js 5512912: src/flux/stores/thread-counts-store.js 91821594: src/flux/edgehill-api.js 91919008: src/flux/stores/recently-read-store.js 5501930: src/flux/models/mutable-query-subscription.js 5471010: src/flux/stores/task-queue-status-store.js 91852488: src/flux/models/unread-query-subscription.js 5512912: src/flux/stores/thread-counts-store.js 91919008: src/flux/stores/recently-read-store.js 5501930: src/flux/models/mutable-query-subscription.js 4417589: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/store.js 91852488: src/flux/models/unread-query-subscription.js 4420430: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/memstore.js 4425944: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/permuteDomain.js 4428210: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/lib/pathMatch.js 4430645: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tough-cookie/package.json 5680865: src/flux/stores/draft-store.js 4432858: node_modules/request/lib/helpers.js 4434482: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/json-stringify-safe/stringify.js 4435389: node_modules/request/request.js 5704584: src/flux/stores/draft-editing-session.js 5886976: src/extension-registry.js 5895610: src/extensions/composer-extension-adapter.js 80567623: node_modules/request/node_modules/bl/bl.js 5860903: src/dom-utils.js 80636139: node_modules/request/node_modules/bl/node_modules/readable-stream/duplex.js 80636191: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_duplex.js 5680865: src/flux/stores/draft-store.js 75226954: node_modules/process-nextick-args/index.js 80638643: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_readable.js 5913732: src/extensions/extension-utils.js 5915158: src/extensions/message-view-extension-adapter.js 5704584: src/flux/stores/draft-editing-session.js 57417682: node_modules/isarray/index.js 5886976: src/extension-registry.js 91896596: src/flux/stores/draft-factory.js 80670635: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_writable.js 5895610: src/extensions/composer-extension-adapter.js 5714320: src/flux/stores/contact-store.js 81345592: node_modules/request/node_modules/hawk/lib/index.js 5860903: src/dom-utils.js 81416906: node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js 5723311: src/flux/stores/contact-ranking-store.js 5913732: src/extensions/extension-utils.js 81490930: node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js 5915158: src/extensions/message-view-extension-adapter.js 5523481: src/window-bridge.js 91896596: src/flux/stores/draft-factory.js 5714320: src/flux/stores/contact-store.js 5917902: src/flux/stores/message-store.js 5723311: src/flux/stores/contact-ranking-store.js 5733766: src/flux/stores/focused-content-store.js 5523481: src/window-bridge.js 5756110: src/services/inline-style-transformer.js 81488262: node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js 81520773: node_modules/request/node_modules/hawk/node_modules/sntp/index.js 5917902: src/flux/stores/message-store.js 81520807: node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js 5758660: src/services/sanitize-transformer.js 5763630: node_modules/sanitize-html/package.json 5733766: src/flux/stores/focused-content-store.js 81345973: node_modules/request/node_modules/hawk/lib/server.js 5765975: node_modules/sanitize-html/index.js 81428267: node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js 5775765: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/index.js 81342006: node_modules/request/node_modules/hawk/lib/crypto.js 81364519: node_modules/request/node_modules/hawk/lib/utils.js 5777529: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Parser.js 81331415: node_modules/request/node_modules/hawk/lib/client.js 5756110: src/services/inline-style-transformer.js 5785458: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Tokenizer.js 80480692: node_modules/request/node_modules/aws-sign2/index.js 81551606: node_modules/request/node_modules/http-signature/lib/index.js 81552232: node_modules/request/node_modules/http-signature/lib/parser.js 5810958: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/lib/decode_codepoint.js 81585919: node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js 5758660: src/services/sanitize-transformer.js 5811580: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/decode.json 5811878: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/entities.json 5763630: node_modules/sanitize-html/package.json 5765975: node_modules/sanitize-html/index.js 81574938: node_modules/request/node_modules/http-signature/lib/utils.js 5775765: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/index.js 81887698: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/index.js 81888429: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/key.js 5777529: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Parser.js 81950012: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/assert.js 5852494: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/legacy.json 5785458: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Tokenizer.js 5854241: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/xml.json 81830178: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/algs.js 5854294: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/index.js 5810958: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/lib/decode_codepoint.js 5858733: node_modules/juice/node_modules/cheerio/node_modules/css-select/node_modules/domutils/node_modules/domelementtype/index.js 81847974: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/fingerprint.js 5811580: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/decode.json 5859144: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/node.js 5811878: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/entities.json 81845672: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/errors.js 5860059: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/element.js 81911179: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/utils.js 5860502: node_modules/sanitize-html/node_modules/regexp-quote/regexp-quote.js 81895828: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/private-key.js 5860597: src/flux/models/message-utils.js 81901963: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/signature.js 92019120: src/flux/tasks/syncback-draft-files-task.js 81942773: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/index.js 92064500: src/multi-request-progress-monitor.js 81928490: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/index.js 5852494: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/legacy.json 81928251: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/errors.js 5555349: src/flux/tasks/destroy-draft-task.js 81934548: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/types.js 81928959: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/reader.js 5854241: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/xml.json 81935186: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js 5854294: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/index.js 81908010: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ssh-buffer.js 5858733: node_modules/juice/node_modules/cheerio/node_modules/css-select/node_modules/domutils/node_modules/domelementtype/index.js 6145019: src/flux/stores/modal-store.js 5859144: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/node.js 81843337: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ed-compat.js 4488696: node_modules/react/package.json 81851404: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/auto.js 5860059: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/element.js 4490634: node_modules/react/react.js 81853302: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pem.js 4490690: node_modules/react/lib/React.js 5860502: node_modules/sanitize-html/node_modules/regexp-quote/regexp-quote.js 79997473: node_modules/react/node_modules/object-assign/index.js 81858111: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs1.js 5860597: src/flux/models/message-utils.js 4503558: node_modules/react/lib/ReactChildren.js 92019120: src/flux/tasks/syncback-draft-files-task.js 4509426: node_modules/react/lib/PooledClass.js 81865807: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs8.js 92064500: src/multi-request-progress-monitor.js 77945402: node_modules/react/node_modules/fbjs/lib/invariant.js 4515504: node_modules/react/lib/ReactElement.js 81881346: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh-private.js 5555349: src/flux/tasks/destroy-draft-task.js 81877740: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/rfc4253.js 4526119: node_modules/react/lib/ReactCurrentOwner.js 77997237: node_modules/react/node_modules/fbjs/lib/warning.js 77865983: node_modules/react/node_modules/fbjs/lib/emptyFunction.js 81884606: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh.js 77610157: node_modules/react/lib/canDefineProperty.js 81835020: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/dhe.js 4526776: node_modules/react/lib/traverseAllChildren.js 6145019: src/flux/stores/modal-store.js 4549078: node_modules/react/lib/getIteratorFn.js 4488696: node_modules/react/package.json 81562004: node_modules/request/node_modules/http-signature/lib/signer.js 4554180: node_modules/react/lib/ReactComponent.js 4490634: node_modules/react/react.js 77543851: node_modules/react/lib/ReactNoopUpdateQueue.js 4490690: node_modules/react/lib/React.js 77541351: node_modules/react/lib/ReactInstrumentation.js 81602307: node_modules/request/node_modules/http-signature/node_modules/jsprim/lib/jsprim.js 77520716: node_modules/react/lib/ReactDebugTool.js 79997473: node_modules/react/node_modules/object-assign/index.js 4503558: node_modules/react/lib/ReactChildren.js 77541813: node_modules/react/lib/ReactInvalidSetStateWarningDevTool.js 81632804: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/lib/extsprintf.js 4509426: node_modules/react/lib/PooledClass.js 77868121: node_modules/react/node_modules/fbjs/lib/emptyObject.js 81797823: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/lib/verror.js 4658325: node_modules/react/lib/ReactClass.js 77945402: node_modules/react/node_modules/fbjs/lib/invariant.js 4515504: node_modules/react/lib/ReactElement.js 81763963: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/lib/validate.js 4622568: node_modules/react/lib/ReactPropTypeLocations.js 4526119: node_modules/react/lib/ReactCurrentOwner.js 77955086: node_modules/react/node_modules/fbjs/lib/keyMirror.js 77997237: node_modules/react/node_modules/fbjs/lib/warning.js 81577777: node_modules/request/node_modules/http-signature/lib/verify.js 77865983: node_modules/react/node_modules/fbjs/lib/emptyFunction.js 4623120: node_modules/react/lib/ReactPropTypeLocationNames.js 77610157: node_modules/react/lib/canDefineProperty.js 77961237: node_modules/react/node_modules/fbjs/lib/keyOf.js 82371286: node_modules/request/node_modules/mime-types/index.js 4526776: node_modules/react/lib/traverseAllChildren.js 77505957: node_modules/react/lib/ReactDOMFactories.js 82530510: node_modules/request/node_modules/mime-types/node_modules/mime-db/index.js 4611818: node_modules/react/lib/ReactElementValidator.js 4549078: node_modules/react/lib/getIteratorFn.js 82387545: node_modules/request/node_modules/mime-types/node_modules/mime-db/db.json 4554180: node_modules/react/lib/ReactComponent.js 77963437: node_modules/react/node_modules/fbjs/lib/mapObject.js 77543851: node_modules/react/lib/ReactNoopUpdateQueue.js 77541351: node_modules/react/lib/ReactInstrumentation.js 77520716: node_modules/react/lib/ReactDebugTool.js 77541813: node_modules/react/lib/ReactInvalidSetStateWarningDevTool.js 77868121: node_modules/react/node_modules/fbjs/lib/emptyObject.js 4658325: node_modules/react/lib/ReactClass.js 4622568: node_modules/react/lib/ReactPropTypeLocations.js 77955086: node_modules/react/node_modules/fbjs/lib/keyMirror.js 5328125: node_modules/react/lib/ReactPropTypes.js 4623120: node_modules/react/lib/ReactPropTypeLocationNames.js 77961237: node_modules/react/node_modules/fbjs/lib/keyOf.js 77505957: node_modules/react/lib/ReactDOMFactories.js 77568528: node_modules/react/lib/ReactVersion.js 4611818: node_modules/react/lib/ReactElementValidator.js 5544770: node_modules/react/lib/onlyChild.js 75786540: node_modules/react-dom/package.json 75786477: node_modules/react-dom/index.js 77963437: node_modules/react/node_modules/fbjs/lib/mapObject.js 4476422: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/stringstream/stringstream.js 4693093: node_modules/react/lib/ReactDOM.js 80754327: node_modules/request/node_modules/caseless/index.js 77494923: node_modules/react/lib/ReactDOMComponentTree.js 4954924: node_modules/react/lib/DOMProperty.js 80801324: node_modules/request/node_modules/forever-agent/index.js 77494452: node_modules/react/lib/ReactDOMComponentFlags.js 5154239: node_modules/react/lib/ReactDefaultInjection.js 5157979: node_modules/react/lib/BeforeInputEventPlugin.js 80814876: node_modules/request/node_modules/form-data/lib/form_data.js 4501390: node_modules/react/lib/EventConstants.js 80764215: node_modules/request/node_modules/combined-stream/lib/combined_stream.js 5171831: node_modules/react/lib/EventPropagators.js 80773528: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js 5034693: node_modules/react/lib/EventPluginHub.js 5328125: node_modules/react/lib/ReactPropTypes.js 5042578: node_modules/react/lib/EventPluginRegistry.js 80944514: node_modules/request/node_modules/form-data/node_modules/async/lib/async.js 4493310: node_modules/react/lib/EventPluginUtils.js 77568528: node_modules/react/lib/ReactVersion.js 4684789: node_modules/react/lib/ReactErrorUtils.js 5544770: node_modules/react/lib/onlyChild.js 5051772: node_modules/react/lib/accumulateInto.js 75786540: node_modules/react-dom/package.json 5053515: node_modules/react/lib/forEachAccumulated.js 75786477: node_modules/react-dom/index.js 77682133: node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js 4693093: node_modules/react/lib/ReactDOM.js 5177151: node_modules/react/lib/FallbackCompositionState.js 77494923: node_modules/react/lib/ReactDOMComponentTree.js 80826033: node_modules/request/node_modules/form-data/lib/populate.js 5179621: node_modules/react/lib/getTextContentAccessor.js 82348558: node_modules/request/node_modules/isstream/isstream.js 4954924: node_modules/react/lib/DOMProperty.js 5185473: node_modules/react/lib/SyntheticCompositionEvent.js 82341499: node_modules/request/node_modules/is-typedarray/index.js 5186617: node_modules/react/lib/SyntheticEvent.js 77494452: node_modules/react/lib/ReactDOMComponentFlags.js 4479214: node_modules/request/lib/getProxyFromURI.js 5154239: node_modules/react/lib/ReactDefaultInjection.js 4481482: node_modules/request/lib/querystring.js 5157979: node_modules/react/lib/BeforeInputEventPlugin.js 5236171: node_modules/react/lib/SyntheticInputEvent.js 82587962: node_modules/request/node_modules/qs/lib/index.js 82593363: node_modules/request/node_modules/qs/lib/stringify.js 5241892: node_modules/react/lib/ChangeEventPlugin.js 4501390: node_modules/react/lib/EventConstants.js 82597342: node_modules/request/node_modules/qs/lib/utils.js 5171831: node_modules/react/lib/EventPropagators.js 4571389: node_modules/react/lib/ReactUpdates.js 5034693: node_modules/react/lib/EventPluginHub.js 82588115: node_modules/request/node_modules/qs/lib/parse.js 5042578: node_modules/react/lib/EventPluginRegistry.js 4580474: node_modules/react/lib/CallbackQueue.js 4482815: node_modules/request/lib/har.js 77540690: node_modules/react/lib/ReactFeatureFlags.js 4493310: node_modules/react/lib/EventPluginUtils.js 4583141: node_modules/react/lib/ReactPerf.js 81001381: node_modules/request/node_modules/har-validator/lib/index.js 4590060: node_modules/react/lib/ReactReconciler.js 81163939: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/index.js 4684789: node_modules/react/lib/ReactErrorUtils.js 4599068: node_modules/react/lib/ReactRef.js 81001935: node_modules/request/node_modules/har-validator/lib/runner.js 5051772: node_modules/react/lib/accumulateInto.js 4608257: node_modules/react/lib/ReactOwner.js 5053515: node_modules/react/lib/forEachAccumulated.js 81005359: node_modules/request/node_modules/har-validator/lib/schemas/index.js 4626735: node_modules/react/lib/Transaction.js 77682133: node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js 81002525: node_modules/request/node_modules/har-validator/lib/schemas/cache.json 5177151: node_modules/react/lib/FallbackCompositionState.js 81002712: node_modules/request/node_modules/har-validator/lib/schemas/cacheEntry.json 5230693: node_modules/react/lib/getEventTarget.js 81003206: node_modules/request/node_modules/har-validator/lib/schemas/content.json 5179621: node_modules/react/lib/getTextContentAccessor.js 81003583: node_modules/request/node_modules/har-validator/lib/schemas/cookie.json 5056054: node_modules/react/lib/isEventSupported.js 81004081: node_modules/request/node_modules/har-validator/lib/schemas/creator.json 5185473: node_modules/react/lib/SyntheticCompositionEvent.js 81004311: node_modules/request/node_modules/har-validator/lib/schemas/entry.json 5253386: node_modules/react/lib/isTextInputElement.js 5186617: node_modules/react/lib/SyntheticEvent.js 81005242: node_modules/request/node_modules/har-validator/lib/schemas/har.json 81007111: node_modules/request/node_modules/har-validator/lib/schemas/log.json 81007604: node_modules/request/node_modules/har-validator/lib/schemas/page.json 81008181: node_modules/request/node_modules/har-validator/lib/schemas/pageTimings.json 81008406: node_modules/request/node_modules/har-validator/lib/schemas/postData.json 5254419: node_modules/react/lib/DefaultEventPluginOrder.js 81009060: node_modules/request/node_modules/har-validator/lib/schemas/record.json 5236171: node_modules/react/lib/SyntheticInputEvent.js 81009286: node_modules/request/node_modules/har-validator/lib/schemas/request.json 5255683: node_modules/react/lib/EnterLeaveEventPlugin.js 81010139: node_modules/request/node_modules/har-validator/lib/schemas/response.json 81010946: node_modules/request/node_modules/har-validator/lib/schemas/timings.json 5241892: node_modules/react/lib/ChangeEventPlugin.js 5259147: node_modules/react/lib/SyntheticMouseEvent.js 81001195: node_modules/request/node_modules/har-validator/lib/error.js 5261327: node_modules/react/lib/SyntheticUIEvent.js 81108729: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/index.js 4571389: node_modules/react/lib/ReactUpdates.js 5055413: node_modules/react/lib/ViewportMetrics.js 5262952: node_modules/react/lib/getEventModifierState.js 4580474: node_modules/react/lib/CallbackQueue.js 5264226: node_modules/react/lib/HTMLDOMPropertyConfig.js 77540690: node_modules/react/lib/ReactFeatureFlags.js 81132607: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/index.js 4583141: node_modules/react/lib/ReactPerf.js 81134601: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/is-property.js 4965198: node_modules/react/lib/ReactComponentBrowserEnvironment.js 4590060: node_modules/react/lib/ReactReconciler.js 4981199: node_modules/react/lib/DOMChildrenOperations.js 4599068: node_modules/react/lib/ReactRef.js 81127606: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/index.js 4608257: node_modules/react/lib/ReactOwner.js 77469073: node_modules/react/lib/DOMLazyTree.js 4626735: node_modules/react/lib/Transaction.js 81149530: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/jsonpointer.js 77613716: node_modules/react/lib/createMicrosoftUnsafeLocalFunction.js 4525735: node_modules/babel-core/node_modules/output-file-sync/node_modules/xtend/immutable.js 4994328: node_modules/react/lib/setTextContent.js 81106380: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/formats.js 4964346: node_modules/react/lib/escapeTextContentForBrowser.js 4995531: node_modules/react/lib/setInnerHTML.js 5230693: node_modules/react/lib/getEventTarget.js 5056054: node_modules/react/lib/isEventSupported.js 4533728: node_modules/request/lib/auth.js 4986498: node_modules/react/lib/Danger.js 5253386: node_modules/react/lib/isTextInputElement.js 4550226: node_modules/request/lib/oauth.js 77856589: node_modules/react/node_modules/fbjs/lib/createNodesFromMarkup.js 5254419: node_modules/react/lib/DefaultEventPluginOrder.js 77848650: node_modules/react/node_modules/fbjs/lib/createArrayFromMixed.js 5255683: node_modules/react/lib/EnterLeaveEventPlugin.js 82544802: node_modules/request/node_modules/oauth-sign/index.js 77922333: node_modules/react/node_modules/fbjs/lib/getMarkupWrap.js 5259147: node_modules/react/lib/SyntheticMouseEvent.js 4568756: node_modules/request/lib/multipart.js 5261327: node_modules/react/lib/SyntheticUIEvent.js 4585628: node_modules/request/lib/redirect.js 4594531: node_modules/request/lib/tunnel.js 5055413: node_modules/react/lib/ViewportMetrics.js 5262952: node_modules/react/lib/getEventModifierState.js 4993464: node_modules/react/lib/ReactMultiChildUpdateTypes.js 4601413: node_modules/less-cache/node_modules/less/node_modules/request/node_modules/tunnel-agent/index.js 5264226: node_modules/react/lib/HTMLDOMPropertyConfig.js 4966626: node_modules/react/lib/ReactDOMIDOperations.js 91866084: src/flux/nylas-long-connection.js 5100253: node_modules/react/lib/ReactDOMComponent.js 4965198: node_modules/react/lib/ReactComponentBrowserEnvironment.js 4981199: node_modules/react/lib/DOMChildrenOperations.js 77469073: node_modules/react/lib/DOMLazyTree.js 77613716: node_modules/react/lib/createMicrosoftUnsafeLocalFunction.js 2376215: node_modules/event-kit/package.json 4994328: node_modules/react/lib/setTextContent.js 4964346: node_modules/react/lib/escapeTextContentForBrowser.js 77468440: node_modules/react/lib/AutoFocusUtils.js 4995531: node_modules/react/lib/setInnerHTML.js 3905749: src/flux/models/account.js 77909940: node_modules/react/node_modules/fbjs/lib/focusNode.js 4986498: node_modules/react/lib/Danger.js 4967813: node_modules/react/lib/CSSPropertyOperations.js 3911874: src/flux/models/model-with-metadata.js 77856589: node_modules/react/node_modules/fbjs/lib/createNodesFromMarkup.js 4974604: node_modules/react/lib/CSSProperty.js 77848650: node_modules/react/node_modules/fbjs/lib/createArrayFromMixed.js 77922333: node_modules/react/node_modules/fbjs/lib/getMarkupWrap.js 77831606: node_modules/react/node_modules/fbjs/lib/camelizeStyleName.js 77830175: node_modules/react/node_modules/fbjs/lib/camelize.js 4993464: node_modules/react/lib/ReactMultiChildUpdateTypes.js 3959955: src/flux/models/message.js 4978298: node_modules/react/lib/dangerousStyleValue.js 4966626: node_modules/react/lib/ReactDOMIDOperations.js 77943412: node_modules/react/node_modules/fbjs/lib/hyphenateStyleName.js 3971136: node_modules/moment/package.json 5100253: node_modules/react/lib/ReactDOMComponent.js 77941796: node_modules/react/node_modules/fbjs/lib/hyphenate.js 77967845: node_modules/react/node_modules/fbjs/lib/memoizeStringOnly.js 3809622: src/flux/models/file.js 77472180: node_modules/react/lib/DOMNamespaces.js 4947570: node_modules/react/lib/DOMPropertyOperations.js 3870842: src/flux/models/event.js 77468440: node_modules/react/lib/AutoFocusUtils.js 77509750: node_modules/react/lib/ReactDOMInstrumentation.js 3875483: src/flux/models/contact.js 77502083: node_modules/react/lib/ReactDOMDebugTool.js 77514692: node_modules/react/lib/ReactDOMUnknownPropertyDevtool.js 77909940: node_modules/react/node_modules/fbjs/lib/focusNode.js 4967813: node_modules/react/lib/CSSPropertyOperations.js 3886010: src/regexp-utils.js 4963597: node_modules/react/lib/quoteAttributeValueForBrowser.js 5022146: node_modules/react/lib/ReactBrowserEventEmitter.js 4974604: node_modules/react/lib/CSSProperty.js 56664169: node_modules/emoji-data/lib/emoji_data.js 56662240: node_modules/emoji-data/lib/emoji_char.js 5054412: node_modules/react/lib/ReactEventEmitterMixin.js 77617819: node_modules/react/lib/getVendorPrefixedEventName.js 56691400: node_modules/emoji-data/node_modules/underscore.string/lib/underscore.string.js 77831606: node_modules/react/node_modules/fbjs/lib/camelizeStyleName.js 77830175: node_modules/react/node_modules/fbjs/lib/camelize.js 5303529: node_modules/react/lib/ReactDOMButton.js 4978298: node_modules/react/lib/dangerousStyleValue.js 5313340: node_modules/react/lib/ReactDOMInput.js 77943412: node_modules/react/node_modules/fbjs/lib/hyphenateStyleName.js 5322982: node_modules/react/lib/LinkedValueUtils.js 77941796: node_modules/react/node_modules/fbjs/lib/hyphenate.js 77967845: node_modules/react/node_modules/fbjs/lib/memoizeStringOnly.js 5379029: node_modules/react/lib/ReactDOMOption.js 77472180: node_modules/react/lib/DOMNamespaces.js 5382256: node_modules/react/lib/ReactDOMSelect.js 4947570: node_modules/react/lib/DOMPropertyOperations.js 5405374: node_modules/react/lib/ReactDOMTextarea.js 77509750: node_modules/react/lib/ReactDOMInstrumentation.js 77502083: node_modules/react/lib/ReactDOMDebugTool.js 5134927: node_modules/react/lib/ReactMultiChild.js 77514692: node_modules/react/lib/ReactDOMUnknownPropertyDevtool.js 4963597: node_modules/react/lib/quoteAttributeValueForBrowser.js 5097145: node_modules/react/lib/ReactComponentEnvironment.js 5147906: node_modules/react/lib/ReactChildReconciler.js 5022146: node_modules/react/lib/ReactBrowserEventEmitter.js 5061495: node_modules/react/lib/instantiateReactComponent.js 5054412: node_modules/react/lib/ReactEventEmitterMixin.js 5065922: node_modules/react/lib/ReactCompositeComponent.js 77617819: node_modules/react/lib/getVendorPrefixedEventName.js 5303529: node_modules/react/lib/ReactDOMButton.js 4567499: node_modules/react/lib/ReactInstanceMap.js 5313340: node_modules/react/lib/ReactDOMInput.js 77542853: node_modules/react/lib/ReactNodeTypes.js 4559113: node_modules/react/lib/ReactUpdateQueue.js 5322982: node_modules/react/lib/LinkedValueUtils.js 5098804: node_modules/react/lib/shouldUpdateReactComponent.js 5379029: node_modules/react/lib/ReactDOMOption.js 5058027: node_modules/react/lib/ReactEmptyComponent.js 5382256: node_modules/react/lib/ReactDOMSelect.js 4623734: node_modules/react/lib/ReactNativeComponent.js 5152586: node_modules/react/lib/flattenChildren.js 5405374: node_modules/react/lib/ReactDOMTextarea.js 5134927: node_modules/react/lib/ReactMultiChild.js 77987568: node_modules/react/node_modules/fbjs/lib/shallowEqual.js 77629907: node_modules/react/lib/validateDOMNesting.js 5097145: node_modules/react/lib/ReactComponentEnvironment.js 5147906: node_modules/react/lib/ReactChildReconciler.js 5061495: node_modules/react/lib/instantiateReactComponent.js 77503986: node_modules/react/lib/ReactDOMEmptyComponent.js 5065922: node_modules/react/lib/ReactCompositeComponent.js 77510993: node_modules/react/lib/ReactDOMTreeTraversal.js 4941549: node_modules/react/lib/ReactDOMTextComponent.js 5271987: node_modules/react/lib/ReactDefaultBatchingStrategy.js 4567499: node_modules/react/lib/ReactInstanceMap.js 77542853: node_modules/react/lib/ReactNodeTypes.js 5411190: node_modules/react/lib/ReactEventListener.js 4559113: node_modules/react/lib/ReactUpdateQueue.js 77676891: node_modules/react/node_modules/fbjs/lib/EventListener.js 5098804: node_modules/react/lib/shouldUpdateReactComponent.js 5058027: node_modules/react/lib/ReactEmptyComponent.js 77934933: node_modules/react/node_modules/fbjs/lib/getUnboundedScrollPosition.js 4623734: node_modules/react/lib/ReactNativeComponent.js 5416577: node_modules/react/lib/ReactInjection.js 5152586: node_modules/react/lib/flattenChildren.js 5426571: node_modules/react/lib/ReactReconcileTransaction.js 5447146: node_modules/react/lib/ReactInputSelection.js 77987568: node_modules/react/node_modules/fbjs/lib/shallowEqual.js 5451456: node_modules/react/lib/ReactDOMSelection.js 77629907: node_modules/react/lib/validateDOMNesting.js 5458269: node_modules/react/lib/getNodeForCharacterOffset.js 77503986: node_modules/react/lib/ReactDOMEmptyComponent.js 77836612: node_modules/react/node_modules/fbjs/lib/containsNode.js 77951977: node_modules/react/node_modules/fbjs/lib/isTextNode.js 77510993: node_modules/react/lib/ReactDOMTreeTraversal.js 77950580: node_modules/react/node_modules/fbjs/lib/isNode.js 4941549: node_modules/react/lib/ReactDOMTextComponent.js 77913930: node_modules/react/node_modules/fbjs/lib/getActiveElement.js 5530086: node_modules/react/lib/SVGDOMPropertyConfig.js 5271987: node_modules/react/lib/ReactDefaultBatchingStrategy.js 3889367: src/flux/stores/account-store.js 5411190: node_modules/react/lib/ReactEventListener.js 77676891: node_modules/react/node_modules/fbjs/lib/EventListener.js 77934933: node_modules/react/node_modules/fbjs/lib/getUnboundedScrollPosition.js 5416577: node_modules/react/lib/ReactInjection.js 65006241: node_modules/keytar/package.json 5426571: node_modules/react/lib/ReactReconcileTransaction.js 65004180: node_modules/keytar/lib/keytar.js 5447146: node_modules/react/lib/ReactInputSelection.js 5451456: node_modules/react/lib/ReactDOMSelection.js 5458269: node_modules/react/lib/getNodeForCharacterOffset.js 5474425: node_modules/react/lib/SelectEventPlugin.js 77836612: node_modules/react/node_modules/fbjs/lib/containsNode.js 77951977: node_modules/react/node_modules/fbjs/lib/isTextNode.js 77950580: node_modules/react/node_modules/fbjs/lib/isNode.js 5480910: node_modules/react/lib/SimpleEventPlugin.js 77913930: node_modules/react/node_modules/fbjs/lib/getActiveElement.js 5530086: node_modules/react/lib/SVGDOMPropertyConfig.js 77602647: node_modules/react/lib/SyntheticAnimationEvent.js 5499613: node_modules/react/lib/SyntheticClipboardEvent.js 5500825: node_modules/react/lib/SyntheticFocusEvent.js 5508624: node_modules/react/lib/SyntheticKeyboardEvent.js 5511371: node_modules/react/lib/getEventCharCode.js 5519469: node_modules/react/lib/getEventKey.js 5522372: node_modules/react/lib/SyntheticDragEvent.js 5526795: node_modules/react/lib/SyntheticTouchEvent.js 77603899: node_modules/react/lib/SyntheticTransitionEvent.js 5528111: node_modules/react/lib/SyntheticWheelEvent.js 5474425: node_modules/react/lib/SelectEventPlugin.js 5480910: node_modules/react/lib/SimpleEventPlugin.js 4998763: node_modules/react/lib/ReactMount.js 77602647: node_modules/react/lib/SyntheticAnimationEvent.js 5499613: node_modules/react/lib/SyntheticClipboardEvent.js 5500825: node_modules/react/lib/SyntheticFocusEvent.js 77501092: node_modules/react/lib/ReactDOMContainerInfo.js 77509290: node_modules/react/lib/ReactDOMFeatureFlags.js 5508624: node_modules/react/lib/SyntheticKeyboardEvent.js 5058770: node_modules/react/lib/ReactMarkupChecksum.js 5511371: node_modules/react/lib/getEventCharCode.js 5519469: node_modules/react/lib/getEventKey.js 5060281: node_modules/react/lib/adler32.js 5269677: node_modules/react/lib/findDOMNode.js 5522372: node_modules/react/lib/SyntheticDragEvent.js 5526795: node_modules/react/lib/SyntheticTouchEvent.js 77616438: node_modules/react/lib/getNativeComponentFromComposite.js 77627726: node_modules/react/lib/renderSubtreeIntoContainer.js 77603899: node_modules/react/lib/SyntheticTransitionEvent.js 5528111: node_modules/react/lib/SyntheticWheelEvent.js 4998763: node_modules/react/lib/ReactMount.js 77501092: node_modules/react/lib/ReactDOMContainerInfo.js 77509290: node_modules/react/lib/ReactDOMFeatureFlags.js 5058770: node_modules/react/lib/ReactMarkupChecksum.js 5060281: node_modules/react/lib/adler32.js 5269677: node_modules/react/lib/findDOMNode.js 77616438: node_modules/react/lib/getNativeComponentFromComposite.js 77627726: node_modules/react/lib/renderSubtreeIntoContainer.js 5634095: src/global/nylas-component-kit.js 3925080: src/flux/models/label.js 5634095: src/global/nylas-component-kit.js 3930438: src/flux/models/folder.js 3930638: src/flux/models/thread.js 6135910: src/flux/stores/popover-store.js 91364936: src/components/fixed-popover.js 4096909: src/flux/models/calendar.js 5951047: src/flux/stores/badge-store.js 5726955: src/flux/stores/focused-perspective-store.js 5744701: src/flux/stores/workspace-store.js 5932960: src/flux/stores/metadata-store.js 4648657: src/flux/stores/category-store.js 6135910: src/flux/stores/popover-store.js 9942964: src/flux/stores/nylas-sync-status-store.js 91364936: src/components/fixed-popover.js 5541756: src/flux/stores/undo-redo-store.js 5614032: src/flux/stores/mail-rules-store.js 4098495: src/flux/models/json-blob.js 5592720: src/flux/tasks/reprocess-mail-rules-task.js 5605792: src/mail-rules-processor.js 5621142: src/mail-rules-templates.js 5629111: src/components/scenario-editor-models.js 5932960: src/flux/stores/metadata-store.js 5541756: src/flux/stores/undo-redo-store.js 5941725: src/flux/stores/file-upload-store.js 5614032: src/flux/stores/mail-rules-store.js 5592720: src/flux/tasks/reprocess-mail-rules-task.js 1894875: node_modules/mkdirp/package.json 1896279: node_modules/mkdirp/index.js 5605792: src/mail-rules-processor.js 5621142: src/mail-rules-templates.js 5629111: src/components/scenario-editor-models.js 5941725: src/flux/stores/file-upload-store.js 4100089: src/mailbox-perspective.js 1894875: node_modules/mkdirp/package.json 1896279: node_modules/mkdirp/index.js 4120446: src/flux/tasks/task-factory.js 4139229: src/flux/tasks/change-folder-task.js 4156736: src/flux/tasks/change-mail-task.js 4636283: src/flux/tasks/syncback-category-task.js 5273907: src/flux/tasks/change-labels-task.js 5304677: src/flux/tasks/change-unread-task.js 5341333: src/flux/tasks/change-starred-task.js 5350052: src/flux/stores/outbox-store.js 5960988: src/flux/stores/file-download-store.js 5356198: src/flux/tasks/send-draft-task.js 5417961: src/sound-registry.js 5975123: node_modules/request-progress/package.json 91943581: src/flux/tasks/base-draft-task.js 5976554: node_modules/request-progress/index.js 5978608: node_modules/request-progress/node_modules/throttleit/index.js 5419733: src/flux/tasks/syncback-metadata-task.js 5431422: src/flux/tasks/syncback-model-task.js 91991403: src/flux/tasks/notify-plugins-of-send-task.js 91821594: src/flux/edgehill-api.js 5960988: src/flux/stores/file-download-store.js 5975123: node_modules/request-progress/package.json 5976554: node_modules/request-progress/index.js 5471010: src/flux/stores/task-queue-status-store.js 5978608: node_modules/request-progress/node_modules/throttleit/index.js 5986780: src/flux/stores/preferences-ui-store.js 5512912: src/flux/stores/thread-counts-store.js 5990595: node_modules/immutable/package.json 5992964: node_modules/immutable/dist/immutable.js 91919008: src/flux/stores/recently-read-store.js 5501930: src/flux/models/mutable-query-subscription.js 91852488: src/flux/models/unread-query-subscription.js 5986780: src/flux/stores/preferences-ui-store.js 5990595: node_modules/immutable/package.json 5992964: node_modules/immutable/dist/immutable.js 5680865: src/flux/stores/draft-store.js 5704584: src/flux/stores/draft-editing-session.js 5886976: src/extension-registry.js 5895610: src/extensions/composer-extension-adapter.js 5860903: src/dom-utils.js 5913732: src/extensions/extension-utils.js 5915158: src/extensions/message-view-extension-adapter.js 91896596: src/flux/stores/draft-factory.js 5714320: src/flux/stores/contact-store.js 5723311: src/flux/stores/contact-ranking-store.js 6183183: src/flux/stores/message-body-processor.js 5523481: src/window-bridge.js 5979358: src/flux/stores/focused-contacts-store.js 5917902: src/flux/stores/message-store.js 6153847: src/flux/stores/searchable-component-store.js 5733766: src/flux/stores/focused-content-store.js 94875052: src/searchable-components/search-constants.js 3672501: keymaps/base.json 6183183: src/flux/stores/message-body-processor.js 5756110: src/services/inline-style-transformer.js 5979358: src/flux/stores/focused-contacts-store.js 5758660: src/services/sanitize-transformer.js 5763630: node_modules/sanitize-html/package.json 6153847: src/flux/stores/searchable-component-store.js 5765975: node_modules/sanitize-html/index.js 94875052: src/searchable-components/search-constants.js 5775765: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/index.js 5777529: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Parser.js 3672501: keymaps/base.json 5785458: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/lib/Tokenizer.js 3674831: keymaps/base-darwin.json 5810958: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/lib/decode_codepoint.js 5811580: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/decode.json 3675274: keymaps/templates/Gmail.json 5811878: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/entities.json 5852494: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/legacy.json 5854241: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/entities/maps/xml.json 3675274: keymaps/templates/Gmail.json 3674831: keymaps/base-darwin.json 5854294: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/index.js 3682264: src/less-compile-cache.js 5858733: node_modules/juice/node_modules/cheerio/node_modules/css-select/node_modules/domutils/node_modules/domelementtype/index.js 3675274: keymaps/templates/Gmail.json 3684143: node_modules/less-cache/lib/less-cache.js 5859144: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/node.js 5860059: node_modules/juice/node_modules/cheerio/node_modules/htmlparser2/node_modules/domhandler/lib/element.js 3693157: node_modules/less-cache/node_modules/less/lib/less/fs.js 5860502: node_modules/sanitize-html/node_modules/regexp-quote/regexp-quote.js 3693264: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/graceful-fs.js 5860597: src/flux/models/message-utils.js 3696362: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/fs.js 92019120: src/flux/tasks/syncback-draft-files-task.js 92064500: src/multi-request-progress-monitor.js 5555349: src/flux/tasks/destroy-draft-task.js 3675274: keymaps/templates/Gmail.json 3682264: src/less-compile-cache.js 3684143: node_modules/less-cache/lib/less-cache.js 6145019: src/flux/stores/modal-store.js 3696740: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/polyfills.js 3693157: node_modules/less-cache/node_modules/less/lib/less/fs.js 4488696: node_modules/react/package.json 3693264: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/graceful-fs.js 4490634: node_modules/react/react.js 4490690: node_modules/react/lib/React.js 3696362: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/fs.js 79997473: node_modules/react/node_modules/object-assign/index.js 3703233: node_modules/jasmine-tagged/node_modules/jasmine-focused/node_modules/walkdir/walkdir.js 4503558: node_modules/react/lib/ReactChildren.js 4509426: node_modules/react/lib/PooledClass.js 77945402: node_modules/react/node_modules/fbjs/lib/invariant.js 4515504: node_modules/react/lib/ReactElement.js 4526119: node_modules/react/lib/ReactCurrentOwner.js 77997237: node_modules/react/node_modules/fbjs/lib/warning.js 77865983: node_modules/react/node_modules/fbjs/lib/emptyFunction.js 3696740: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/polyfills.js 77610157: node_modules/react/lib/canDefineProperty.js 4526776: node_modules/react/lib/traverseAllChildren.js 4549078: node_modules/react/lib/getIteratorFn.js 3703233: node_modules/jasmine-tagged/node_modules/jasmine-focused/node_modules/walkdir/walkdir.js 4554180: node_modules/react/lib/ReactComponent.js 77543851: node_modules/react/lib/ReactNoopUpdateQueue.js 77541351: node_modules/react/lib/ReactInstrumentation.js 77520716: node_modules/react/lib/ReactDebugTool.js 77541813: node_modules/react/lib/ReactInvalidSetStateWarningDevTool.js 77868121: node_modules/react/node_modules/fbjs/lib/emptyObject.js 4658325: node_modules/react/lib/ReactClass.js 4622568: node_modules/react/lib/ReactPropTypeLocations.js 77955086: node_modules/react/node_modules/fbjs/lib/keyMirror.js 4623120: node_modules/react/lib/ReactPropTypeLocationNames.js 77961237: node_modules/react/node_modules/fbjs/lib/keyOf.js 77505957: node_modules/react/lib/ReactDOMFactories.js 4611818: node_modules/react/lib/ReactElementValidator.js 77963437: node_modules/react/node_modules/fbjs/lib/mapObject.js 5328125: node_modules/react/lib/ReactPropTypes.js 77568528: node_modules/react/lib/ReactVersion.js 5544770: node_modules/react/lib/onlyChild.js 75786540: node_modules/react-dom/package.json 75786477: node_modules/react-dom/index.js 4693093: node_modules/react/lib/ReactDOM.js 77494923: node_modules/react/lib/ReactDOMComponentTree.js 4954924: node_modules/react/lib/DOMProperty.js 77494452: node_modules/react/lib/ReactDOMComponentFlags.js 5154239: node_modules/react/lib/ReactDefaultInjection.js 5157979: node_modules/react/lib/BeforeInputEventPlugin.js 4501390: node_modules/react/lib/EventConstants.js 5171831: node_modules/react/lib/EventPropagators.js 5034693: node_modules/react/lib/EventPluginHub.js 5042578: node_modules/react/lib/EventPluginRegistry.js 4493310: node_modules/react/lib/EventPluginUtils.js 4684789: node_modules/react/lib/ReactErrorUtils.js 5051772: node_modules/react/lib/accumulateInto.js 5053515: node_modules/react/lib/forEachAccumulated.js 77682133: node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js 5177151: node_modules/react/lib/FallbackCompositionState.js 5179621: node_modules/react/lib/getTextContentAccessor.js 5185473: node_modules/react/lib/SyntheticCompositionEvent.js 5186617: node_modules/react/lib/SyntheticEvent.js 5236171: node_modules/react/lib/SyntheticInputEvent.js 5241892: node_modules/react/lib/ChangeEventPlugin.js 4571389: node_modules/react/lib/ReactUpdates.js 4580474: node_modules/react/lib/CallbackQueue.js 77540690: node_modules/react/lib/ReactFeatureFlags.js 4583141: node_modules/react/lib/ReactPerf.js 4590060: node_modules/react/lib/ReactReconciler.js 4599068: node_modules/react/lib/ReactRef.js 4608257: node_modules/react/lib/ReactOwner.js 4626735: node_modules/react/lib/Transaction.js 5230693: node_modules/react/lib/getEventTarget.js 5056054: node_modules/react/lib/isEventSupported.js 5253386: node_modules/react/lib/isTextInputElement.js 5254419: node_modules/react/lib/DefaultEventPluginOrder.js 5255683: node_modules/react/lib/EnterLeaveEventPlugin.js 5259147: node_modules/react/lib/SyntheticMouseEvent.js 5261327: node_modules/react/lib/SyntheticUIEvent.js 5055413: node_modules/react/lib/ViewportMetrics.js 5262952: node_modules/react/lib/getEventModifierState.js 5264226: node_modules/react/lib/HTMLDOMPropertyConfig.js 4965198: node_modules/react/lib/ReactComponentBrowserEnvironment.js 4981199: node_modules/react/lib/DOMChildrenOperations.js 77469073: node_modules/react/lib/DOMLazyTree.js 77613716: node_modules/react/lib/createMicrosoftUnsafeLocalFunction.js 4994328: node_modules/react/lib/setTextContent.js 4964346: node_modules/react/lib/escapeTextContentForBrowser.js 4995531: node_modules/react/lib/setInnerHTML.js 4986498: node_modules/react/lib/Danger.js 77856589: node_modules/react/node_modules/fbjs/lib/createNodesFromMarkup.js 77848650: node_modules/react/node_modules/fbjs/lib/createArrayFromMixed.js 77922333: node_modules/react/node_modules/fbjs/lib/getMarkupWrap.js 4993464: node_modules/react/lib/ReactMultiChildUpdateTypes.js 4966626: node_modules/react/lib/ReactDOMIDOperations.js 5100253: node_modules/react/lib/ReactDOMComponent.js 77468440: node_modules/react/lib/AutoFocusUtils.js 77909940: node_modules/react/node_modules/fbjs/lib/focusNode.js 4967813: node_modules/react/lib/CSSPropertyOperations.js 4974604: node_modules/react/lib/CSSProperty.js 77831606: node_modules/react/node_modules/fbjs/lib/camelizeStyleName.js 77830175: node_modules/react/node_modules/fbjs/lib/camelize.js 4978298: node_modules/react/lib/dangerousStyleValue.js 77943412: node_modules/react/node_modules/fbjs/lib/hyphenateStyleName.js 77941796: node_modules/react/node_modules/fbjs/lib/hyphenate.js 77967845: node_modules/react/node_modules/fbjs/lib/memoizeStringOnly.js 77472180: node_modules/react/lib/DOMNamespaces.js 4947570: node_modules/react/lib/DOMPropertyOperations.js 77509750: node_modules/react/lib/ReactDOMInstrumentation.js 77502083: node_modules/react/lib/ReactDOMDebugTool.js 77514692: node_modules/react/lib/ReactDOMUnknownPropertyDevtool.js 4963597: node_modules/react/lib/quoteAttributeValueForBrowser.js 5022146: node_modules/react/lib/ReactBrowserEventEmitter.js 5054412: node_modules/react/lib/ReactEventEmitterMixin.js 77617819: node_modules/react/lib/getVendorPrefixedEventName.js 5303529: node_modules/react/lib/ReactDOMButton.js 5313340: node_modules/react/lib/ReactDOMInput.js 5322982: node_modules/react/lib/LinkedValueUtils.js 5379029: node_modules/react/lib/ReactDOMOption.js 5382256: node_modules/react/lib/ReactDOMSelect.js 5405374: node_modules/react/lib/ReactDOMTextarea.js 5134927: node_modules/react/lib/ReactMultiChild.js 5097145: node_modules/react/lib/ReactComponentEnvironment.js 5147906: node_modules/react/lib/ReactChildReconciler.js 5061495: node_modules/react/lib/instantiateReactComponent.js 5065922: node_modules/react/lib/ReactCompositeComponent.js 4567499: node_modules/react/lib/ReactInstanceMap.js 77542853: node_modules/react/lib/ReactNodeTypes.js 4559113: node_modules/react/lib/ReactUpdateQueue.js 5098804: node_modules/react/lib/shouldUpdateReactComponent.js 5058027: node_modules/react/lib/ReactEmptyComponent.js 4623734: node_modules/react/lib/ReactNativeComponent.js 5152586: node_modules/react/lib/flattenChildren.js 77987568: node_modules/react/node_modules/fbjs/lib/shallowEqual.js 77629907: node_modules/react/lib/validateDOMNesting.js 77503986: node_modules/react/lib/ReactDOMEmptyComponent.js 77510993: node_modules/react/lib/ReactDOMTreeTraversal.js 4941549: node_modules/react/lib/ReactDOMTextComponent.js 5271987: node_modules/react/lib/ReactDefaultBatchingStrategy.js 5411190: node_modules/react/lib/ReactEventListener.js 77676891: node_modules/react/node_modules/fbjs/lib/EventListener.js 77934933: node_modules/react/node_modules/fbjs/lib/getUnboundedScrollPosition.js 5416577: node_modules/react/lib/ReactInjection.js 5426571: node_modules/react/lib/ReactReconcileTransaction.js 5447146: node_modules/react/lib/ReactInputSelection.js 5451456: node_modules/react/lib/ReactDOMSelection.js 5458269: node_modules/react/lib/getNodeForCharacterOffset.js 77836612: node_modules/react/node_modules/fbjs/lib/containsNode.js 77951977: node_modules/react/node_modules/fbjs/lib/isTextNode.js 77950580: node_modules/react/node_modules/fbjs/lib/isNode.js 77913930: node_modules/react/node_modules/fbjs/lib/getActiveElement.js 5530086: node_modules/react/lib/SVGDOMPropertyConfig.js 5474425: node_modules/react/lib/SelectEventPlugin.js 5480910: node_modules/react/lib/SimpleEventPlugin.js 77602647: node_modules/react/lib/SyntheticAnimationEvent.js 5499613: node_modules/react/lib/SyntheticClipboardEvent.js 5500825: node_modules/react/lib/SyntheticFocusEvent.js 5508624: node_modules/react/lib/SyntheticKeyboardEvent.js 5511371: node_modules/react/lib/getEventCharCode.js 5519469: node_modules/react/lib/getEventKey.js 5522372: node_modules/react/lib/SyntheticDragEvent.js 5526795: node_modules/react/lib/SyntheticTouchEvent.js 77603899: node_modules/react/lib/SyntheticTransitionEvent.js 5528111: node_modules/react/lib/SyntheticWheelEvent.js 4998763: node_modules/react/lib/ReactMount.js 77501092: node_modules/react/lib/ReactDOMContainerInfo.js 77509290: node_modules/react/lib/ReactDOMFeatureFlags.js 5058770: node_modules/react/lib/ReactMarkupChecksum.js 5060281: node_modules/react/lib/adler32.js 5269677: node_modules/react/lib/findDOMNode.js 77616438: node_modules/react/lib/getNativeComponentFromComposite.js 77627726: node_modules/react/lib/renderSubtreeIntoContainer.js 5634095: src/global/nylas-component-kit.js 6135910: src/flux/stores/popover-store.js 91364936: src/components/fixed-popover.js 5932960: src/flux/stores/metadata-store.js 5541756: src/flux/stores/undo-redo-store.js 5614032: src/flux/stores/mail-rules-store.js 5592720: src/flux/tasks/reprocess-mail-rules-task.js 5605792: src/mail-rules-processor.js 5621142: src/mail-rules-templates.js 5629111: src/components/scenario-editor-models.js 5941725: src/flux/stores/file-upload-store.js 1894875: node_modules/mkdirp/package.json 1896279: node_modules/mkdirp/index.js 5960988: src/flux/stores/file-download-store.js 5975123: node_modules/request-progress/package.json 5976554: node_modules/request-progress/index.js 3708754: static/index.less 5978608: node_modules/request-progress/node_modules/throttleit/index.js 3709902: static/variables/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3719008: static/normalize.less 3726688: static/type.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3731800: static/inputs.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3733216: static/buttons.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3737856: static/dropdowns.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3738091: static/workspace.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3746538: static/resizable.less 3747129: static/selection.less 3747443: static/utilities.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3708754: static/index.less 3717773: static/variables/ui-mixins.less 3748613: static/components/popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3750797: static/components/menu.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3752952: static/components/switch.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3753558: static/components/tokenizing-text-field.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3759326: static/components/extra.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3761494: static/components/list-tabular.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3765991: static/components/disclosure-triangle.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3709902: static/variables/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3717773: static/variables/ui-mixins.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3766478: static/components/button-dropdown.less 3719008: static/normalize.less 3733216: static/buttons.less 3726688: static/type.less 3770706: static/components/scroll-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3731800: static/inputs.less 3773921: static/components/spinner.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3733216: static/buttons.less 3774954: static/components/generated-form.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3776905: static/components/unsafe.less 3717773: static/variables/ui-mixins.less 3737856: static/dropdowns.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3738091: static/workspace.less 3777342: static/components/key-commands-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3777420: static/components/contenteditable.less 3746538: static/resizable.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3747129: static/selection.less 3781503: static/components/editable-list.less 3747443: static/utilities.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3784402: static/components/outline-view.less 3717773: static/variables/ui-mixins.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3748613: static/components/popover.less 3717773: static/variables/ui-mixins.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3750797: static/components/menu.less 3787888: static/components/fixed-popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3790891: static/components/modal.less 3752952: static/components/switch.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791241: static/components/date-input.less 3753558: static/components/tokenizing-text-field.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97491765: static/components/nylas-calendar.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97490322: static/components/empty-list-state.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489398: static/components/date-picker.less 3759326: static/components/extra.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97499252: static/components/time-picker.less 3717773: static/variables/ui-mixins.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3761494: static/components/list-tabular.less 97498180: static/components/table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489787: static/components/editable-table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3765991: static/components/disclosure-triangle.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3766478: static/components/button-dropdown.less 3733216: static/buttons.less 3770706: static/components/scroll-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3773921: static/components/spinner.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3774954: static/components/generated-form.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3776905: static/components/unsafe.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3777342: static/components/key-commands-region.less 3777420: static/components/contenteditable.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3781503: static/components/editable-list.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3784402: static/components/outline-view.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3787888: static/components/fixed-popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3790891: static/components/modal.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791241: static/components/date-input.less 3718416: internal_packages/ui-light/styles/ui-variables.less 5986780: src/flux/stores/preferences-ui-store.js 97491765: static/components/nylas-calendar.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97490322: static/components/empty-list-state.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489398: static/components/date-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97499252: static/components/time-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97498180: static/components/table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489787: static/components/editable-table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 5990595: node_modules/immutable/package.json 5992964: node_modules/immutable/dist/immutable.js 3791399: static/email-frame.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791399: static/email-frame.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6330626: src/sheet-container.js 75770892: node_modules/react-addons-css-transition-group/index.js 6285435: node_modules/react/lib/ReactCSSTransitionGroup.js 6288370: node_modules/react/lib/ReactTransitionGroup.js 6294511: node_modules/react/lib/ReactTransitionChildMapping.js 6300645: node_modules/react/lib/ReactCSSTransitionGroupChild.js 77653837: node_modules/react/node_modules/fbjs/lib/CSSCore.js 6305123: node_modules/react/lib/ReactTransitionEvents.js 6336675: src/sheet.js 3795009: internal_packages/send-later/package.json 6259077: src/component-registry.js 956764: package.json 5658995: src/components/retina-img.js 6345466: src/components/flexbox.js 6347603: src/components/injected-component-set.js 6355674: src/components/unsafe-component.js 6361626: src/components/injected-component-label.js 6363606: src/components/resizable-region.js 6372438: src/sheet-toolbar.js 6183183: src/flux/stores/message-body-processor.js 3795593: internal_packages/nylas-private-analytics/lib/main.js 5979358: src/flux/stores/focused-contacts-store.js 3795926: internal_packages/nylas-private-fonts/stylesheets/nylas-fonts.less 3709902: static/variables/ui-variables.less 3797131: internal_packages/nylas-private-fonts/lib/main.js 6153847: src/flux/stores/searchable-component-store.js 3797276: internal_packages/nylas-private-sounds/lib/main.js 94875052: src/searchable-components/search-constants.js 6217392: internal_packages/screenshot-mode/lib/main.js 3672501: keymaps/base.json 38810714: internal_packages/thread-search-index/lib/main.js 38818707: internal_packages/thread-search-index/lib/search-index-store.js 6218172: internal_packages/deltas/lib/main.js 6218486: internal_packages/deltas/lib/account-delta-connection-pool.js 6226311: internal_packages/deltas/lib/nylas-long-connection.js 3674831: keymaps/base-darwin.json 6234072: internal_packages/deltas/lib/account-delta-connection.js 3675274: keymaps/templates/Gmail.json 6249716: internal_packages/deltas/lib/contact-rankings-cache.js 6251800: internal_packages/deltas/lib/refreshing-json-cache.js 6254175: internal_packages/worker-ui/stylesheets/worker-ui.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6258340: internal_packages/worker-ui/lib/main.js 3675274: keymaps/templates/Gmail.json 3682264: src/less-compile-cache.js 6259077: src/component-registry.js 3684143: node_modules/less-cache/lib/less-cache.js 6267062: internal_packages/worker-ui/lib/developer-bar.js 3693157: node_modules/less-cache/node_modules/less/lib/less/fs.js 3693264: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/graceful-fs.js 3696362: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/fs.js 6311954: internal_packages/worker-ui/lib/developer-bar-store.js 6318392: internal_packages/worker-ui/lib/developer-bar-task.js 6322329: node_modules/classnames/package.json 6323631: node_modules/classnames/index.js 6324643: internal_packages/worker-ui/lib/developer-bar-curl-item.js 3696740: node_modules/less-cache/node_modules/less/node_modules/graceful-fs/polyfills.js 6327819: internal_packages/worker-ui/lib/developer-bar-long-poll-item.js 6330626: src/sheet-container.js 3703233: node_modules/jasmine-tagged/node_modules/jasmine-focused/node_modules/walkdir/walkdir.js 75770892: node_modules/react-addons-css-transition-group/index.js 6285435: node_modules/react/lib/ReactCSSTransitionGroup.js 6288370: node_modules/react/lib/ReactTransitionGroup.js 6294511: node_modules/react/lib/ReactTransitionChildMapping.js 6300645: node_modules/react/lib/ReactCSSTransitionGroupChild.js 77653837: node_modules/react/node_modules/fbjs/lib/CSSCore.js 6305123: node_modules/react/lib/ReactTransitionEvents.js 6336675: src/sheet.js 5658995: src/components/retina-img.js 6345466: src/components/flexbox.js 6347603: src/components/injected-component-set.js 6355674: src/components/unsafe-component.js 6361626: src/components/injected-component-label.js 6363606: src/components/resizable-region.js 6372438: src/sheet-toolbar.js 6388649: internal_packages/nylas-private-analytics/lib/analytics-store.js 6395255: internal_packages/nylas-private-analytics/node_modules/underscore/package.json 6397211: internal_packages/nylas-private-analytics/node_modules/underscore/underscore.js 6450130: internal_packages/nylas-private-analytics/node_modules/mixpanel/package.json 6451584: internal_packages/nylas-private-analytics/node_modules/mixpanel/lib/mixpanel-node.js 3709902: static/variables/ui-variables.less 3708754: static/index.less 3709902: static/variables/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3719008: static/normalize.less 3726688: static/type.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3731800: static/inputs.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3733216: static/buttons.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3737856: static/dropdowns.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3738091: static/workspace.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3746538: static/resizable.less 3747129: static/selection.less 3747443: static/utilities.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3748613: static/components/popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3750797: static/components/menu.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3752952: static/components/switch.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3753558: static/components/tokenizing-text-field.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3759326: static/components/extra.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3761494: static/components/list-tabular.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3765991: static/components/disclosure-triangle.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3766478: static/components/button-dropdown.less 3733216: static/buttons.less 3770706: static/components/scroll-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3773921: static/components/spinner.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3774954: static/components/generated-form.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3776905: static/components/unsafe.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3777342: static/components/key-commands-region.less 3777420: static/components/contenteditable.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3781503: static/components/editable-list.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3784402: static/components/outline-view.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3787888: static/components/fixed-popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3790891: static/components/modal.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791241: static/components/date-input.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97491765: static/components/nylas-calendar.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97490322: static/components/empty-list-state.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489398: static/components/date-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97499252: static/components/time-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97498180: static/components/table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489787: static/components/editable-table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791399: static/email-frame.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3795009: internal_packages/send-later/package.json 956764: package.json 4487636: internal_packages/account-sidebar/stylesheets/account-sidebar.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 4488033: internal_packages/account-sidebar/lib/main.js 5625206: internal_packages/account-sidebar/lib/components/account-sidebar.js 5639191: src/components/outline-view.js 5658995: src/components/retina-img.js 6475049: src/components/outline-view-item.js 6322329: node_modules/classnames/package.json 6323631: node_modules/classnames/index.js 6515079: src/components/disclosure-triangle.js 6516563: src/components/drop-zone.js 6519250: src/components/scroll-region.js 6541041: src/components/scrollbar-ticks.js 6345466: src/components/flexbox.js 6259077: src/component-registry.js 6547498: internal_packages/account-sidebar/lib/components/account-switcher.js 6550507: internal_packages/account-sidebar/lib/account-commands.js 6555086: internal_packages/account-sidebar/lib/sidebar-actions.js 6555434: internal_packages/account-sidebar/lib/sidebar-store.js 6561356: internal_packages/account-sidebar/lib/sidebar-section.js 5568947: src/flux/tasks/destroy-category-task.js 6568512: internal_packages/account-sidebar/lib/sidebar-item.js 11121379: internal_packages/activity-list/stylesheets/activity-list.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 11116731: internal_packages/activity-list/lib/main.js 11044916: internal_packages/activity-list/lib/activity-list-button.js 11103679: internal_packages/activity-list/lib/activity-list.js 11078805: internal_packages/activity-list/lib/activity-list-store.js 11043296: internal_packages/activity-list/lib/activity-list-actions.js 11119272: internal_packages/activity-list/lib/plugins.js 11059386: internal_packages/activity-list/lib/activity-list-item-container.js 11054031: internal_packages/activity-list/lib/activity-list-empty-state.js 6576439: internal_packages/attachments/stylesheets/attachments.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6581032: internal_packages/attachments/lib/main.js 6583425: internal_packages/attachments/lib/attachment-component.js 6602716: internal_packages/attachments/lib/image-attachment-component.js 6621086: internal_packages/category-picker/stylesheets/category-picker.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6622362: internal_packages/category-picker/lib/main.js 6622941: internal_packages/category-picker/lib/category-picker.js 6650228: src/components/key-commands-region.js 11125195: internal_packages/category-picker/lib/category-picker-popover.js 6662242: internal_packages/composer/stylesheets/composer.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3733216: static/buttons.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 6672270: internal_packages/composer/lib/main.js 6688298: internal_packages/composer/lib/compose-button.js 6693285: internal_packages/composer/lib/composer-view.js 6801894: internal_packages/composer/lib/file-upload.js 6810718: internal_packages/composer/lib/image-upload.js 6817376: internal_packages/composer/lib/composer-editor.js 15488775: internal_packages/composer/lib/composer-header.js 6881838: internal_packages/composer/lib/account-contact-field.js 6918854: internal_packages/composer/lib/collapsed-participants.js 15477990: internal_packages/composer/lib/composer-header-actions.js 6916905: internal_packages/composer/lib/fields.js 91309256: src/components/decorators/listens-to-flux-store.js 6854571: internal_packages/composer/lib/send-action-button.js 15467409: internal_packages/composer/lib/action-bar-plugins.js 15526379: internal_packages/composer/lib/decorators/inflate-draft-client-id.js 12062174: internal_packages/composer-emoji/stylesheets/composer-emoji.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 11895302: internal_packages/composer-emoji/lib/main.js 11884154: internal_packages/composer-emoji/lib/emoji-store.js 11220121: internal_packages/composer-emoji/lib/emoji-actions.js 11311506: internal_packages/composer-emoji/lib/emoji-data.js 3708754: static/index.less 3709902: static/variables/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3719008: static/normalize.less 3726688: static/type.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3731800: static/inputs.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3733216: static/buttons.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3737856: static/dropdowns.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3738091: static/workspace.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3746538: static/resizable.less 3747129: static/selection.less 3747443: static/utilities.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3748613: static/components/popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3750797: static/components/menu.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3752952: static/components/switch.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3753558: static/components/tokenizing-text-field.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3759326: static/components/extra.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3761494: static/components/list-tabular.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3765991: static/components/disclosure-triangle.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3766478: static/components/button-dropdown.less 3733216: static/buttons.less 3770706: static/components/scroll-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3773921: static/components/spinner.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3774954: static/components/generated-form.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3776905: static/components/unsafe.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3777342: static/components/key-commands-region.less 3777420: static/components/contenteditable.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3781503: static/components/editable-list.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3784402: static/components/outline-view.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3787888: static/components/fixed-popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3790891: static/components/modal.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791241: static/components/date-input.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97491765: static/components/nylas-calendar.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97490322: static/components/empty-list-state.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489398: static/components/date-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97499252: static/components/time-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97498180: static/components/table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489787: static/components/editable-table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791399: static/email-frame.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 11269567: internal_packages/composer-emoji/lib/emoji-composer-extension.js 11874201: internal_packages/composer-emoji/lib/emoji-picker.js 12036836: internal_packages/composer-emoji/node_modules/node-emoji/package.json 11900180: internal_packages/composer-emoji/node_modules/node-emoji/index.js 11900220: internal_packages/composer-emoji/node_modules/node-emoji/lib/emoji.js 11901752: internal_packages/composer-emoji/node_modules/node-emoji/lib/emoji.json 6209520: src/extensions/composer-extension.js 6199449: src/extensions/contenteditable-extension.js 11863789: internal_packages/composer-emoji/lib/emoji-message-extension.js 6216016: src/extensions/message-view-extension.js 11263608: internal_packages/composer-emoji/lib/emoji-button.js 11220330: internal_packages/composer-emoji/lib/emoji-button-popover.js 11197213: internal_packages/composer-emoji/lib/categorized-emoji.js 12365614: internal_packages/composer-mail-merge/stylesheets/mail-merge.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 12246852: internal_packages/composer-mail-merge/lib/main.js 12078922: internal_packages/composer-mail-merge/lib/mail-merge-button.js 12115700: internal_packages/composer-mail-merge/lib/mail-merge-draft-editing-session.js 12255616: internal_packages/composer-mail-merge/lib/table-data-reducer.js 12097808: internal_packages/composer-mail-merge/lib/mail-merge-constants.js 12365120: internal_packages/composer-mail-merge/package.json 12275198: internal_packages/composer-mail-merge/lib/workspace-data-reducer.js 12195717: internal_packages/composer-mail-merge/lib/mail-merge-utils.js 12294536: internal_packages/composer-mail-merge/node_modules/papaparse/package.json 12296719: internal_packages/composer-mail-merge/node_modules/papaparse/papaparse.js 75788185: node_modules/react-dom/server.js 77510224: node_modules/react/lib/ReactDOMServer.js 5537399: node_modules/react/lib/ReactServerRendering.js 77547198: node_modules/react/lib/ReactServerBatchingStrategy.js 5539994: node_modules/react/lib/ReactServerRenderingTransaction.js 12182972: internal_packages/composer-mail-merge/lib/mail-merge-token.js 12164340: internal_packages/composer-mail-merge/lib/mail-merge-send-button.js 12143212: internal_packages/composer-mail-merge/lib/mail-merge-participants-text-field.js 12101370: internal_packages/composer-mail-merge/lib/mail-merge-container.js 12224650: internal_packages/composer-mail-merge/lib/mail-merge-workspace.js 12175665: internal_packages/composer-mail-merge/lib/mail-merge-table.js 12133498: internal_packages/composer-mail-merge/lib/mail-merge-header-input.js 91336318: src/components/editable-table.js 91714196: src/components/selectable-table.js 91306664: src/components/decorators/compose.js 91296149: src/components/decorators/auto-focuses.js 91318034: src/components/decorators/listens-to-movement-keys.js 91751055: src/components/table.js 91429095: src/components/lazy-rendered-list.js 12089622: internal_packages/composer-mail-merge/lib/mail-merge-composer-extension.js 12774978: internal_packages/composer-scheduler/stylesheets/scheduler.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 12597570: internal_packages/composer-scheduler/lib/main.js 12401184: internal_packages/composer-scheduler/lib/calendar/proposed-time-event.js 12634143: internal_packages/composer-scheduler/lib/scheduler-actions.js 12637241: internal_packages/composer-scheduler/lib/scheduler-constants.js 12639598: internal_packages/composer-scheduler/package.json 12409433: internal_packages/composer-scheduler/lib/calendar/proposed-time-picker.js 12611238: internal_packages/composer-scheduler/lib/proposed-time-calendar-store.js 12604799: internal_packages/composer-scheduler/lib/proposal.js 67807413: node_modules/moment-round/package.json 67804644: node_modules/moment-round/dist/moment-round.js 12394346: internal_packages/composer-scheduler/lib/calendar/proposed-time-calendar-data-source.js 91490885: src/components/nylas-calendar/calendar-data-source.js 12458476: internal_packages/composer-scheduler/lib/composer/new-event-card-container.js 12472599: internal_packages/composer-scheduler/lib/composer/new-event-card.js 12509765: internal_packages/composer-scheduler/lib/composer/new-event-helper.js 12529558: internal_packages/composer-scheduler/lib/composer/proposed-time-list.js 12435429: internal_packages/composer-scheduler/lib/composer/email-b64-images.js 12557233: internal_packages/composer-scheduler/lib/composer/scheduler-composer-button.js 12577398: internal_packages/composer-scheduler/lib/composer/scheduler-composer-extension.js 12517105: internal_packages/composer-scheduler/lib/composer/new-event-preview.js 6940725: internal_packages/composer-signature/styles/composer-signature.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6942112: internal_packages/composer-signature/lib/main.js 6945805: internal_packages/composer-signature/lib/signature-composer-extension.js 6952671: internal_packages/composer-signature/lib/signature-utils.js 6956430: internal_packages/composer-signature/lib/signature-store.js 12790035: internal_packages/composer-signature/lib/signature-actions.js 6964420: internal_packages/composer-signature/lib/preferences-signatures.js 7087046: internal_packages/composer-spellcheck/lib/main.js 7088733: internal_packages/composer-spellcheck/lib/spellcheck-composer-extension.js 15649511: internal_packages/draft-list/stylesheets/draft-list.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 15640684: internal_packages/draft-list/lib/main.js 15634286: internal_packages/draft-list/lib/draft-list.js 10328875: src/components/flux-container.js 91409314: src/components/focus-container.js 91356893: src/components/empty-list-state.js 9573988: src/components/evented-iframe.js 9590240: src/searchable-components/searchable-component-maker.js 9604588: src/searchable-components/virtual-dom-parser.js 9625948: src/searchable-components/search-match.js 9630803: src/searchable-components/unified-dom-parser.js 9656602: src/searchable-components/iframe-searcher.js 9660189: src/searchable-components/real-dom-parser.js 10348470: src/components/multiselect-list.js 10242985: src/components/list-tabular.js 6613819: src/components/spinner.js 10255150: src/components/list-data-source.js 10259550: src/components/list-selection.js 10266495: src/components/list-tabular-item.js 10270866: src/components/swipe-container.js 10361741: src/components/multiselect-list-interaction-handler.js 10365624: src/components/multiselect-split-interaction-handler.js 15622621: internal_packages/draft-list/lib/draft-list-store.js 10317803: src/flux/stores/observable-list-data-source.js 15613521: internal_packages/draft-list/lib/draft-list-columns.js 6347603: src/components/injected-component-set.js 6355674: src/components/unsafe-component.js 6361626: src/components/injected-component-label.js 15626659: internal_packages/draft-list/lib/draft-list-toolbar.js 91329623: src/components/decorators/listens-to-observable.js 15616539: internal_packages/draft-list/lib/draft-list-send-status.js 15647651: internal_packages/draft-list/lib/sending-progress-bar.js 15637453: internal_packages/draft-list/lib/draft-toolbar-buttons.js 8166806: internal_packages/events/stylesheets/events.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 8168831: internal_packages/events/lib/main.js 8169447: internal_packages/events/lib/event-header.js 5545981: src/flux/tasks/event-rsvp-task.js 9406822: internal_packages/link-tracking/stylesheets/main.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9407650: internal_packages/link-tracking/lib/main.js 9411086: internal_packages/link-tracking/lib/link-tracking-button.js 9419481: internal_packages/link-tracking/lib/link-tracking-constants.js 9421038: internal_packages/link-tracking/package.json 9421801: internal_packages/link-tracking/lib/link-tracking-composer-extension.js 9433912: internal_packages/link-tracking/lib/link-tracking-message-extension.js 9443214: internal_packages/message-autoload-images/stylesheets/message-autoload-images.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9443764: internal_packages/message-autoload-images/lib/main.js 9447860: internal_packages/message-autoload-images/lib/autoload-images-extension.js 9452536: internal_packages/message-autoload-images/lib/autoload-images-store.js 9464787: internal_packages/message-autoload-images/lib/autoload-images-actions.js 9466378: internal_packages/message-autoload-images/lib/autoload-images-header.js 9475435: internal_packages/message-list/stylesheets/find-in-thread.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9476423: internal_packages/message-list/stylesheets/message-list.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9492060: internal_packages/message-list/lib/main.js 9493451: internal_packages/message-list/lib/message-list.js 9514819: internal_packages/message-list/lib/find-in-thread.js 9533550: internal_packages/message-list/lib/message-item-container.js 9538634: internal_packages/message-list/lib/message-item.js 9554145: internal_packages/message-list/lib/email-frame.js 21971387: internal_packages/message-list/lib/autolinker.js 21985271: internal_packages/message-list/lib/autoscale-images.js 9674883: internal_packages/message-list/lib/email-frame-styles-store.js 9677072: internal_packages/message-list/lib/message-participants.js 9684453: internal_packages/message-list/lib/message-item-body.js 10181263: src/canvas-utils.js 6774422: src/services/quoted-html-transformer.js 6783209: src/services/quote-string-detector.js 6789262: src/dom-walkers.js 9691982: internal_packages/message-list/lib/message-timestamp.js 9694947: internal_packages/message-list/lib/message-controls.js 6876890: src/components/button-dropdown.js 6626794: src/components/menu.js 6791782: src/components/injected-component.js 9704877: src/components/mail-label-set.js 6659234: src/components/mail-label.js 9717628: src/components/mail-important-icon.js 9723341: internal_packages/message-list/lib/message-list-hidden-messages-toggle.js 22004384: internal_packages/message-list/lib/sidebar-plugin-container.js 21992491: internal_packages/message-list/lib/sidebar-participant-picker.js 9914437: internal_packages/mode-switch/stylesheets/mode-switch.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9914642: internal_packages/mode-switch/lib/main.js 9915888: internal_packages/mode-switch/lib/mode-toggle.js 9918736: internal_packages/notification-mailto/lib/main.js 9920876: src/default-client-helper.js 9923701: internal_packages/notification-update-available/stylesheets/release-bar.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9924225: internal_packages/notification-update-available/lib/main.js 9927264: internal_packages/notifications/stylesheets/notifications.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9931964: internal_packages/notifications/lib/main.js 25522410: internal_packages/notifications/lib/sidebar/activity-sidebar.js 75770954: node_modules/react-addons-css-transition-group/package.json 75770892: node_modules/react-addons-css-transition-group/index.js 6285435: node_modules/react/lib/ReactCSSTransitionGroup.js 6288370: node_modules/react/lib/ReactTransitionGroup.js 6294511: node_modules/react/lib/ReactTransitionChildMapping.js 6300645: node_modules/react/lib/ReactCSSTransitionGroupChild.js 77653837: node_modules/react/node_modules/fbjs/lib/CSSCore.js 6305123: node_modules/react/lib/ReactTransitionEvents.js 9936813: internal_packages/notifications/lib/notifications-store.js 25534637: internal_packages/notifications/lib/sidebar/streaming-sync-activity.js 25528307: internal_packages/notifications/lib/sidebar/initial-sync-activity.js 25500590: internal_packages/notifications/lib/headers/connection-status-header.js 25486624: internal_packages/notifications/lib/headers/account-error-header.js 25515642: internal_packages/notifications/lib/headers/notifications-header.js 25518220: internal_packages/notifications/lib/headers/notifications-item.js 3795593: internal_packages/nylas-private-analytics/lib/main.js 3795926: internal_packages/nylas-private-fonts/stylesheets/nylas-fonts.less 3709902: static/variables/ui-variables.less 3797131: internal_packages/nylas-private-fonts/lib/main.js 3797276: internal_packages/nylas-private-sounds/lib/main.js 9948811: internal_packages/open-tracking/stylesheets/main.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 9949921: internal_packages/open-tracking/lib/main.js 9954068: internal_packages/open-tracking/lib/open-tracking-button.js 9962734: internal_packages/open-tracking/lib/open-tracking-constants.js 9964291: internal_packages/open-tracking/package.json 9965050: internal_packages/open-tracking/lib/open-tracking-icon.js 9974239: internal_packages/open-tracking/lib/open-tracking-message-status.js 9983231: internal_packages/open-tracking/lib/open-tracking-composer-extension.js 29621096: internal_packages/participant-profile/stylesheets/participant-profile.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 27770485: internal_packages/participant-profile/lib/main.js 27771226: internal_packages/participant-profile/lib/participant-profile-store.js 27766292: internal_packages/participant-profile/lib/clearbit-data-source.js 27772813: internal_packages/participant-profile/lib/sidebar-participant-profile.js 27794981: internal_packages/participant-profile/lib/sidebar-related-threads.js 10002861: internal_packages/plugins/stylesheets/plugins.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10005819: internal_packages/plugins/lib/main.js 10584362: internal_packages/plugins/lib/preferences-plugins.js 10591138: internal_packages/plugins/lib/tabs-store.js 10593603: internal_packages/plugins/lib/plugins-actions.js 10595942: internal_packages/plugins/lib/tabs.js 10597146: internal_packages/plugins/lib/tab-installed.js 10612734: internal_packages/plugins/lib/package-set.js 10619274: internal_packages/plugins/lib/package.js 10636183: internal_packages/plugins/lib/packages-store.js 10007988: internal_packages/preferences/stylesheets/preferences-accounts.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10010736: internal_packages/preferences/stylesheets/preferences-mail-rules.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10013552: internal_packages/preferences/stylesheets/preferences.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10018740: internal_packages/preferences/lib/main.js 10942956: internal_packages/preferences/lib/preferences-root.js 36888774: internal_packages/preferences/lib/preferences-tabs-bar.js 10678179: internal_packages/preferences/lib/tabs/preferences-general.js 10687249: internal_packages/preferences/lib/tabs/config-schema-item.js 10702281: internal_packages/preferences/lib/tabs/workspace-section.js 10744972: internal_packages/preferences/lib/tabs/sending-section.js 10752957: internal_packages/preferences/lib/tabs/preferences-accounts.js 10763596: internal_packages/preferences/lib/tabs/preferences-account-list.js 10775702: internal_packages/preferences/lib/tabs/preferences-account-details.js 36901668: internal_packages/preferences/lib/tabs/preferences-appearance.js 10803666: internal_packages/preferences/lib/tabs/preferences-keymaps.js 10835061: internal_packages/preferences/lib/tabs/preferences-mail-rules.js 10027324: internal_packages/print/lib/main.js 10028732: internal_packages/print/lib/printer.js 10034622: internal_packages/print/lib/print-window.js 36971547: internal_packages/remove-tracking-pixels/lib/main.js 6217392: internal_packages/screenshot-mode/lib/main.js 10043968: internal_packages/send-and-archive/styles/send-and-archive.less 3709902: static/variables/ui-variables.less 10043990: internal_packages/send-and-archive/lib/main.js 10044567: internal_packages/send-and-archive/lib/send-and-archive-extension.js 3795009: internal_packages/send-later/package.json 10046563: internal_packages/send-later/stylesheets/send-later.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10047505: internal_packages/send-later/lib/main.js 37038743: internal_packages/send-later/lib/send-later-button.js 10048157: internal_packages/send-later/lib/send-later-popover.js 10062336: src/date-utils.js 10080490: node_modules/chrono-node/src/chrono.js 10082187: node_modules/chrono-node/src/options.js 10084390: node_modules/chrono-node/src/parsers/parser.js 10087416: node_modules/chrono-node/src/parsers/EN/ENISOFormatParser.js 10090699: node_modules/chrono-node/src/result.js 10094393: node_modules/chrono-node/src/parsers/EN/ENDeadlineFormatParser.js 10096163: node_modules/chrono-node/src/parsers/EN/ENMonthNameLittleEndianParser.js 10099767: node_modules/chrono-node/src/utils/EN.js 10100643: node_modules/chrono-node/src/parsers/EN/ENMonthNameMiddleEndianParser.js 54657192: node_modules/chrono-node/src/parsers/EN/ENMonthNameParser.js 10104644: node_modules/chrono-node/src/parsers/EN/ENSlashDateFormatParser.js 10107976: node_modules/chrono-node/src/parsers/EN/ENSlashDateFormatStartWithYearParser.js 54659809: node_modules/chrono-node/src/parsers/EN/ENSlashMonthFormatParser.js 10109509: node_modules/chrono-node/src/parsers/EN/ENTimeAgoFormatParser.js 10112162: node_modules/chrono-node/src/parsers/EN/ENTimeExpressionParser.js 10119452: node_modules/chrono-node/src/parsers/EN/ENWeekdayParser.js 10122038: node_modules/chrono-node/src/parsers/EN/ENCasualDateParser.js 10124502: node_modules/chrono-node/src/parsers/JP/JPStandardParser.js 10127111: node_modules/chrono-node/src/utils/JP.js 10128540: node_modules/chrono-node/src/parsers/JP/JPCasualDateParser.js 54661209: node_modules/chrono-node/src/parsers/ES/ESCasualDateParser.js 54664898: node_modules/chrono-node/src/parsers/ES/ESDeadlineFormatParser.js 54673468: node_modules/chrono-node/src/parsers/ES/ESTimeAgoFormatParser.js 54675930: node_modules/chrono-node/src/parsers/ES/ESTimeExpressionParser.js 54682534: node_modules/chrono-node/src/parsers/ES/ESWeekdayParser.js 54666650: node_modules/chrono-node/src/parsers/ES/ESMonthNameLittleEndianParser.js 54686880: node_modules/chrono-node/src/utils/ES.js 54670068: node_modules/chrono-node/src/parsers/ES/ESSlashDateFormatParser.js 10130127: node_modules/chrono-node/src/refiners/refiner.js 10131338: node_modules/chrono-node/src/refiners/OverlapRemovalRefiner.js 10132351: node_modules/chrono-node/src/refiners/ExtractTimezoneOffsetRefiner.js 10133766: node_modules/chrono-node/src/refiners/ExtractTimezoneAbbrRefiner.js 10137202: node_modules/chrono-node/src/refiners/UnlikelyFormatFilter.js 10137518: node_modules/chrono-node/src/refiners/EN/ENMergeDateTimeRefiner.js 10141811: node_modules/chrono-node/src/refiners/EN/ENMergeDateRangeRefiner.js 10144348: node_modules/chrono-node/src/refiners/JP/JPMergeDateRangeRefiner.js 10061936: internal_packages/send-later/lib/send-later-actions.js 10062177: internal_packages/send-later/lib/send-later-constants.js 3795009: internal_packages/send-later/package.json 10144604: internal_packages/send-later/lib/send-later-store.js 10146708: internal_packages/send-later/lib/send-later-status.js 10154325: internal_packages/sidebar-fullcontact/stylesheets/sidebar-fullcontact.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10155637: internal_packages/sidebar-fullcontact/lib/main.js 10156198: internal_packages/sidebar-fullcontact/lib/sidebar-fullcontact.js 10158666: internal_packages/sidebar-fullcontact/lib/fullcontact-store.js 10160817: internal_packages/sidebar-fullcontact/lib/sidebar-fullcontact-details.js 10169244: internal_packages/system-tray/lib/main.js 10170796: internal_packages/system-tray/lib/system-tray-icon-store.js 37317747: internal_packages/theme-picker/styles/theme-picker.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10189521: internal_packages/theme-picker/lib/main.js 10189999: internal_packages/theme-picker/lib/theme-picker.js 10205690: internal_packages/theme-picker/lib/theme-option.js 38809494: internal_packages/thread-list/stylesheets/selected-items-stack.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10222854: internal_packages/thread-list/stylesheets/thread-list.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10235013: internal_packages/thread-list/lib/main.js 10331274: internal_packages/thread-list/lib/thread-list.js 10370299: internal_packages/thread-list/lib/thread-list-columns.js 10379446: internal_packages/thread-list/lib/thread-list-quick-actions.js 10383457: internal_packages/thread-list/lib/thread-list-participants.js 10238079: internal_packages/thread-list/lib/thread-list-store.js 10313585: internal_packages/thread-list/lib/thread-list-data-source.js 10389852: internal_packages/thread-list/lib/thread-list-icon.js 10393161: internal_packages/thread-list/lib/thread-list-scroll-tooltip.js 10395728: internal_packages/thread-list/lib/thread-list-context-menu.js 10414166: internal_packages/thread-list/lib/category-removal-target-rulesets.js 38750037: internal_packages/thread-list/lib/thread-list-toolbar.js 38717639: internal_packages/thread-list/lib/injects-toolbar-buttons.js 38726612: internal_packages/thread-list/lib/message-list-toolbar.js 38735117: internal_packages/thread-list/lib/selected-items-stack.js 38756427: internal_packages/thread-list/lib/thread-toolbar-buttons.js 38900474: internal_packages/thread-search/stylesheets/search-bar.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 38846525: internal_packages/thread-search/lib/main.js 38848780: internal_packages/thread-search/lib/search-bar.js 38890613: internal_packages/thread-search/lib/search-store.js 38848436: internal_packages/thread-search/lib/search-actions.js 38857942: internal_packages/thread-search/lib/search-mailbox-perspective.js 38869907: internal_packages/thread-search/lib/search-query-subscription.js 10422956: internal_packages/thread-snooze/stylesheets/snooze-mail-label.less 3709902: static/variables/ui-variables.less 10423117: internal_packages/thread-snooze/stylesheets/snooze-popover.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10424653: internal_packages/thread-snooze/lib/main.js 39002329: internal_packages/thread-snooze/lib/snooze-buttons.js 10425464: internal_packages/thread-snooze/lib/snooze-popover.js 10439168: internal_packages/thread-snooze/lib/snooze-actions.js 10439380: internal_packages/thread-snooze/lib/snooze-mail-label.js 10448736: internal_packages/thread-snooze/lib/snooze-constants.js 10448947: internal_packages/thread-snooze/package.json 10449468: internal_packages/thread-snooze/lib/snooze-utils.js 10453553: internal_packages/thread-snooze/lib/snooze-store.js 10456694: internal_packages/undo-redo/stylesheets/undo-redo.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 10458145: internal_packages/undo-redo/lib/main.js 10458810: internal_packages/undo-redo/lib/undo-redo-component.js 10463691: internal_packages/unread-notifications/lib/main.js 10471380: src/native-notifications.js 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 6330626: src/sheet-container.js 6336675: src/sheet.js 6363606: src/components/resizable-region.js 6372438: src/sheet-toolbar.js 94914523: src/task.js 6388649: internal_packages/nylas-private-analytics/lib/analytics-store.js 6395255: internal_packages/nylas-private-analytics/node_modules/underscore/package.json 6397211: internal_packages/nylas-private-analytics/node_modules/underscore/underscore.js 6450130: internal_packages/nylas-private-analytics/node_modules/mixpanel/package.json 6451584: internal_packages/nylas-private-analytics/node_modules/mixpanel/lib/mixpanel-node.js 3709902: static/variables/ui-variables.less 1973294: src/compile-cache.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 3708754: static/index.less 3709902: static/variables/ui-variables.less 3717773: static/variables/ui-mixins.less 3717937: static/mixins/common-ui-elements.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3718450: static/mixins/text-emphasis.less 3718566: static/mixins/background-variant.less 3718705: static/mixins/windows.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3719008: static/normalize.less 3726688: static/type.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3731800: static/inputs.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 3733216: static/buttons.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3737856: static/dropdowns.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3738091: static/workspace.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 3746538: static/resizable.less 3747129: static/selection.less 3747443: static/utilities.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3748613: static/components/popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3750797: static/components/menu.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3752952: static/components/switch.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3753558: static/components/tokenizing-text-field.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3759326: static/components/extra.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3761494: static/components/list-tabular.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3765991: static/components/disclosure-triangle.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3766478: static/components/button-dropdown.less 3733216: static/buttons.less 3770706: static/components/scroll-region.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3773921: static/components/spinner.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3774954: static/components/generated-form.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3776905: static/components/unsafe.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3777342: static/components/key-commands-region.less 3777420: static/components/contenteditable.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3781503: static/components/editable-list.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3784402: static/components/outline-view.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3717773: static/variables/ui-mixins.less 3787888: static/components/fixed-popover.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3790891: static/components/modal.less 3718416: internal_packages/ui-light/styles/ui-variables.less 3791241: static/components/date-input.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97491765: static/components/nylas-calendar.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97490322: static/components/empty-list-state.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489398: static/components/date-picker.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97499252: static/components/time-picker.less 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 3718416: internal_packages/ui-light/styles/ui-variables.less 97498180: static/components/table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 97489787: static/components/editable-table.less 3718416: internal_packages/ui-light/styles/ui-variables.less 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 3791399: static/email-frame.less 3709902: static/variables/ui-variables.less 3718416: internal_packages/ui-light/styles/ui-variables.less 1853312: node_modules/fs-plus/node_modules/async/package.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1978902: src/compile-support/babel.js 1980527: static/babelrc.json 1980671: src/compile-support/coffee-script.js 1981853: src/compile-support/typescript.js 1983139: node_modules/underscore/package.json 1985095: node_modules/underscore/underscore.js 2038014: node_modules/source-map-support/package.json 2039642: node_modules/source-map-support/source-map-support.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 94911340: src/task-bootstrap.js 2264399: node_modules/emissary/package.json 2266273: node_modules/emissary/lib/emissary.js 2266555: node_modules/emissary/lib/helpers.js 2268129: node_modules/emissary/lib/behavior.js 2272107: node_modules/emissary/node_modules/underscore-plus/package.json 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2288860: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/package.json 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2336063: node_modules/property-accessors/package.json 2337929: node_modules/property-accessors/lib/property-accessors.js 2340201: node_modules/property-accessors/node_modules/mixto/package.json 2341779: node_modules/property-accessors/node_modules/mixto/lib/mixin.js 2343179: node_modules/emissary/lib/signal.js 2352520: node_modules/emissary/lib/emitter.js 2367779: node_modules/emissary/node_modules/mixto/package.json 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 4222287: node_modules/request/package.json 4225420: node_modules/request/index.js 80790165: node_modules/request/node_modules/extend/package.json 80787899: node_modules/request/node_modules/extend/index.js 4229450: node_modules/request/lib/cookies.js 82838107: node_modules/request/node_modules/tough-cookie/package.json 82637881: node_modules/request/node_modules/tough-cookie/lib/cookie.js 82685639: node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js 82835266: node_modules/request/node_modules/tough-cookie/lib/store.js 82675424: node_modules/request/node_modules/tough-cookie/lib/memstore.js 82683373: node_modules/request/node_modules/tough-cookie/lib/permuteDomain.js 82680938: node_modules/request/node_modules/tough-cookie/lib/pathMatch.js 82838107: node_modules/request/node_modules/tough-cookie/package.json 4432858: node_modules/request/lib/helpers.js 82361121: node_modules/request/node_modules/json-stringify-safe/package.json 82362804: node_modules/request/node_modules/json-stringify-safe/stringify.js 4435389: node_modules/request/request.js 80742369: node_modules/request/node_modules/bl/package.json 80567623: node_modules/request/node_modules/bl/bl.js 80636139: node_modules/request/node_modules/bl/node_modules/readable-stream/duplex.js 80636191: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_duplex.js 80720291: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/process-nextick-args/package.json 80718759: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/process-nextick-args/index.js 80705839: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/core-util-is/package.json 80702818: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/core-util-is/lib/util.js 80712444: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/inherits/package.json 80711730: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/inherits/inherits.js 80638643: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_readable.js 80716737: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/isarray/package.json 80716605: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/isarray/index.js 80670635: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_writable.js 80738031: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/util-deprecate/package.json 80737908: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/util-deprecate/node.js 81531974: node_modules/request/node_modules/hawk/package.json 81345592: node_modules/request/node_modules/hawk/lib/index.js 81424556: node_modules/request/node_modules/hawk/node_modules/boom/package.json 81416906: node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js 81515577: node_modules/request/node_modules/hawk/node_modules/hoek/package.json 81490930: node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js 81488262: node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js 81530565: node_modules/request/node_modules/hawk/node_modules/sntp/package.json 81520773: node_modules/request/node_modules/hawk/node_modules/sntp/index.js 81520807: node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js 81345973: node_modules/request/node_modules/hawk/lib/server.js 81429631: node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json 81428267: node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js 81342006: node_modules/request/node_modules/hawk/lib/crypto.js 81364519: node_modules/request/node_modules/hawk/lib/utils.js 81331415: node_modules/request/node_modules/hawk/lib/client.js 80485113: node_modules/request/node_modules/aws-sign2/package.json 80480692: node_modules/request/node_modules/aws-sign2/index.js 82337952: node_modules/request/node_modules/http-signature/package.json 81551606: node_modules/request/node_modules/http-signature/lib/index.js 81552232: node_modules/request/node_modules/http-signature/lib/parser.js 81591249: node_modules/request/node_modules/http-signature/node_modules/assert-plus/package.json 81585919: node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js 81574938: node_modules/request/node_modules/http-signature/lib/utils.js 82335507: node_modules/request/node_modules/http-signature/node_modules/sshpk/package.json 81887698: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/index.js 81888429: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/key.js 81955466: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/package.json 81950012: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/assert.js 81830178: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/algs.js 81847974: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/fingerprint.js 81845672: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/errors.js 81911179: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/utils.js 81895828: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/private-key.js 81901963: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/signature.js 81943093: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/package.json 81942773: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/index.js 81928490: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/index.js 81928251: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/errors.js 81934548: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/types.js 81928959: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/reader.js 81935186: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js 81908010: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ssh-buffer.js 81843337: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ed-compat.js 81851404: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/auto.js 81853302: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pem.js 81858111: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs1.js 81865807: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs8.js 81881346: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh-private.js 81877740: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/rfc4253.js 81884606: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh.js 81835020: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/dhe.js 81562004: node_modules/request/node_modules/http-signature/lib/signer.js 81802301: node_modules/request/node_modules/http-signature/node_modules/jsprim/package.json 81602307: node_modules/request/node_modules/http-signature/node_modules/jsprim/lib/jsprim.js 81636568: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/package.json 81632804: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/lib/extsprintf.js 81801412: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/package.json 81797823: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/lib/verror.js 81774451: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/package.json 81763963: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/lib/validate.js 81577777: node_modules/request/node_modules/http-signature/lib/verify.js 82533240: node_modules/request/node_modules/mime-types/package.json 82371286: node_modules/request/node_modules/mime-types/index.js 82530646: node_modules/request/node_modules/mime-types/node_modules/mime-db/package.json 82530510: node_modules/request/node_modules/mime-types/node_modules/mime-db/index.js 82387545: node_modules/request/node_modules/mime-types/node_modules/mime-db/db.json 82606571: node_modules/request/node_modules/stringstream/package.json 82607891: node_modules/request/node_modules/stringstream/stringstream.js 80756086: node_modules/request/node_modules/caseless/package.json 80754327: node_modules/request/node_modules/caseless/index.js 80805500: node_modules/request/node_modules/forever-agent/package.json 80801324: node_modules/request/node_modules/forever-agent/index.js 80986121: node_modules/request/node_modules/form-data/package.json 80814876: node_modules/request/node_modules/form-data/lib/form_data.js 80777465: node_modules/request/node_modules/combined-stream/package.json 80764215: node_modules/request/node_modules/combined-stream/lib/combined_stream.js 80775847: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/package.json 80773528: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js 80983078: node_modules/request/node_modules/form-data/node_modules/async/package.json 80944514: node_modules/request/node_modules/form-data/node_modules/async/lib/async.js 80826033: node_modules/request/node_modules/form-data/lib/populate.js 82349146: node_modules/request/node_modules/isstream/package.json 82348558: node_modules/request/node_modules/isstream/isstream.js 82342515: node_modules/request/node_modules/is-typedarray/package.json 82341499: node_modules/request/node_modules/is-typedarray/index.js 4479214: node_modules/request/lib/getProxyFromURI.js 4481482: node_modules/request/lib/querystring.js 82601463: node_modules/request/node_modules/qs/package.json 82587962: node_modules/request/node_modules/qs/lib/index.js 82593363: node_modules/request/node_modules/qs/lib/stringify.js 82597342: node_modules/request/node_modules/qs/lib/utils.js 82588115: node_modules/request/node_modules/qs/lib/parse.js 4482815: node_modules/request/lib/har.js 81178912: node_modules/request/node_modules/har-validator/package.json 81001381: node_modules/request/node_modules/har-validator/lib/index.js 81176502: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/package.json 81163939: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/index.js 81001935: node_modules/request/node_modules/har-validator/lib/runner.js 81005359: node_modules/request/node_modules/har-validator/lib/schemas/index.js 81002525: node_modules/request/node_modules/har-validator/lib/schemas/cache.json 81002712: node_modules/request/node_modules/har-validator/lib/schemas/cacheEntry.json 81003206: node_modules/request/node_modules/har-validator/lib/schemas/content.json 81003583: node_modules/request/node_modules/har-validator/lib/schemas/cookie.json 81004081: node_modules/request/node_modules/har-validator/lib/schemas/creator.json 81004311: node_modules/request/node_modules/har-validator/lib/schemas/entry.json 81005242: node_modules/request/node_modules/har-validator/lib/schemas/har.json 81007111: node_modules/request/node_modules/har-validator/lib/schemas/log.json 81007604: node_modules/request/node_modules/har-validator/lib/schemas/page.json 81008181: node_modules/request/node_modules/har-validator/lib/schemas/pageTimings.json 81008406: node_modules/request/node_modules/har-validator/lib/schemas/postData.json 81009060: node_modules/request/node_modules/har-validator/lib/schemas/record.json 81009286: node_modules/request/node_modules/har-validator/lib/schemas/request.json 81010139: node_modules/request/node_modules/har-validator/lib/schemas/response.json 81010946: node_modules/request/node_modules/har-validator/lib/schemas/timings.json 81001195: node_modules/request/node_modules/har-validator/lib/error.js 81161590: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/package.json 81108729: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/index.js 81147021: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/package.json 81132607: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/index.js 81145615: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/package.json 81134601: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/is-property.js 81128902: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/package.json 81127606: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/index.js 81151111: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/package.json 81149530: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/jsonpointer.js 81158029: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/xtend/package.json 81157276: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/xtend/immutable.js 81106380: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/formats.js 4533728: node_modules/request/lib/auth.js 1962761: node_modules/node-uuid/package.json 1964629: node_modules/node-uuid/uuid.js 4550226: node_modules/request/lib/oauth.js 82548387: node_modules/request/node_modules/oauth-sign/package.json 82544802: node_modules/request/node_modules/oauth-sign/index.js 4568756: node_modules/request/lib/multipart.js 4585628: node_modules/request/lib/redirect.js 4594531: node_modules/request/lib/tunnel.js 82856379: node_modules/request/node_modules/tunnel-agent/package.json 82849535: node_modules/request/node_modules/tunnel-agent/index.js 3599638: src/apm-wrapper.js 3613961: src/buffered-process.js 94914523: src/task.js 1973294: src/compile-cache.js 1766806: node_modules/fs-plus/package.json 1768751: node_modules/fs-plus/lib/fs-plus.js 1789356: node_modules/fs-plus/node_modules/underscore-plus/package.json 1791321: node_modules/fs-plus/node_modules/underscore-plus/lib/underscore-plus.js 1806109: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/package.json 1807823: node_modules/fs-plus/node_modules/underscore-plus/node_modules/underscore/underscore.js 1853312: node_modules/fs-plus/node_modules/async/package.json 1854649: node_modules/fs-plus/node_modules/async/lib/async.js 1884050: node_modules/fs-plus/node_modules/mkdirp/package.json 1885107: node_modules/fs-plus/node_modules/mkdirp/index.js 1887478: node_modules/fs-plus/node_modules/rimraf/package.json 1889121: node_modules/fs-plus/node_modules/rimraf/rimraf.js 1978902: src/compile-support/babel.js 1980527: static/babelrc.json 1980671: src/compile-support/coffee-script.js 1981853: src/compile-support/typescript.js 1983139: node_modules/underscore/package.json 1985095: node_modules/underscore/underscore.js 2038014: node_modules/source-map-support/package.json 2039642: node_modules/source-map-support/source-map-support.js 2054178: node_modules/source-map-support/node_modules/source-map/package.json 2057217: node_modules/source-map-support/node_modules/source-map/lib/source-map.js 2057643: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-generator.js 2070902: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/package.json 2072148: node_modules/source-map-support/node_modules/source-map/node_modules/amdefine/amdefine.js 2082064: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64-vlq.js 2086956: node_modules/source-map-support/node_modules/source-map/lib/source-map/base64.js 2088093: node_modules/source-map-support/node_modules/source-map/lib/source-map/util.js 2093422: node_modules/source-map-support/node_modules/source-map/lib/source-map/array-set.js 2096140: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-map-consumer.js 2113947: node_modules/source-map-support/node_modules/source-map/lib/source-map/binary-search.js 2117157: node_modules/source-map-support/node_modules/source-map/lib/source-map/source-node.js 94911340: src/task-bootstrap.js 2264399: node_modules/emissary/package.json 2266273: node_modules/emissary/lib/emissary.js 2266555: node_modules/emissary/lib/helpers.js 2268129: node_modules/emissary/lib/behavior.js 2272107: node_modules/emissary/node_modules/underscore-plus/package.json 2274072: node_modules/emissary/node_modules/underscore-plus/lib/underscore-plus.js 2288860: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/package.json 2290574: node_modules/emissary/node_modules/underscore-plus/node_modules/underscore/underscore.js 2336063: node_modules/property-accessors/package.json 2337929: node_modules/property-accessors/lib/property-accessors.js 2340201: node_modules/property-accessors/node_modules/mixto/package.json 2341779: node_modules/property-accessors/node_modules/mixto/lib/mixin.js 2343179: node_modules/emissary/lib/signal.js 2352520: node_modules/emissary/lib/emitter.js 2367779: node_modules/emissary/node_modules/mixto/package.json 2369463: node_modules/emissary/node_modules/mixto/lib/mixin.js 2370863: node_modules/emissary/lib/subscriber.js 2374948: node_modules/emissary/lib/subscription.js 4222287: node_modules/request/package.json 4225420: node_modules/request/index.js 80790165: node_modules/request/node_modules/extend/package.json 80787899: node_modules/request/node_modules/extend/index.js 4229450: node_modules/request/lib/cookies.js 82838107: node_modules/request/node_modules/tough-cookie/package.json 82637881: node_modules/request/node_modules/tough-cookie/lib/cookie.js 82685639: node_modules/request/node_modules/tough-cookie/lib/pubsuffix.js 82835266: node_modules/request/node_modules/tough-cookie/lib/store.js 82675424: node_modules/request/node_modules/tough-cookie/lib/memstore.js 82683373: node_modules/request/node_modules/tough-cookie/lib/permuteDomain.js 82680938: node_modules/request/node_modules/tough-cookie/lib/pathMatch.js 82838107: node_modules/request/node_modules/tough-cookie/package.json 4432858: node_modules/request/lib/helpers.js 82361121: node_modules/request/node_modules/json-stringify-safe/package.json 82362804: node_modules/request/node_modules/json-stringify-safe/stringify.js 4435389: node_modules/request/request.js 80742369: node_modules/request/node_modules/bl/package.json 80567623: node_modules/request/node_modules/bl/bl.js 80636139: node_modules/request/node_modules/bl/node_modules/readable-stream/duplex.js 80636191: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_duplex.js 80720291: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/process-nextick-args/package.json 80718759: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/process-nextick-args/index.js 80705839: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/core-util-is/package.json 80702818: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/core-util-is/lib/util.js 80712444: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/inherits/package.json 80711730: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/inherits/inherits.js 80638643: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_readable.js 80716737: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/isarray/package.json 80716605: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/isarray/index.js 80670635: node_modules/request/node_modules/bl/node_modules/readable-stream/lib/_stream_writable.js 80738031: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/util-deprecate/package.json 80737908: node_modules/request/node_modules/bl/node_modules/readable-stream/node_modules/util-deprecate/node.js 81531974: node_modules/request/node_modules/hawk/package.json 81345592: node_modules/request/node_modules/hawk/lib/index.js 81424556: node_modules/request/node_modules/hawk/node_modules/boom/package.json 81416906: node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js 81515577: node_modules/request/node_modules/hawk/node_modules/hoek/package.json 81490930: node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js 81488262: node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js 81530565: node_modules/request/node_modules/hawk/node_modules/sntp/package.json 81520773: node_modules/request/node_modules/hawk/node_modules/sntp/index.js 81520807: node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js 81345973: node_modules/request/node_modules/hawk/lib/server.js 81429631: node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json 81428267: node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js 81342006: node_modules/request/node_modules/hawk/lib/crypto.js 81364519: node_modules/request/node_modules/hawk/lib/utils.js 81331415: node_modules/request/node_modules/hawk/lib/client.js 80485113: node_modules/request/node_modules/aws-sign2/package.json 80480692: node_modules/request/node_modules/aws-sign2/index.js 82337952: node_modules/request/node_modules/http-signature/package.json 81551606: node_modules/request/node_modules/http-signature/lib/index.js 81552232: node_modules/request/node_modules/http-signature/lib/parser.js 81591249: node_modules/request/node_modules/http-signature/node_modules/assert-plus/package.json 81585919: node_modules/request/node_modules/http-signature/node_modules/assert-plus/assert.js 81574938: node_modules/request/node_modules/http-signature/lib/utils.js 82335507: node_modules/request/node_modules/http-signature/node_modules/sshpk/package.json 81887698: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/index.js 81888429: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/key.js 81955466: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/package.json 81950012: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus/assert.js 81830178: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/algs.js 81847974: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/fingerprint.js 81845672: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/errors.js 81911179: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/utils.js 81895828: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/private-key.js 81901963: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/signature.js 81943093: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/package.json 81942773: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/index.js 81928490: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/index.js 81928251: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/errors.js 81934548: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/types.js 81928959: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/reader.js 81935186: node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js 81908010: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ssh-buffer.js 81843337: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/ed-compat.js 81851404: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/auto.js 81853302: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pem.js 81858111: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs1.js 81865807: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/pkcs8.js 81881346: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh-private.js 81877740: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/rfc4253.js 81884606: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/formats/ssh.js 81835020: node_modules/request/node_modules/http-signature/node_modules/sshpk/lib/dhe.js 81562004: node_modules/request/node_modules/http-signature/lib/signer.js 81802301: node_modules/request/node_modules/http-signature/node_modules/jsprim/package.json 81602307: node_modules/request/node_modules/http-signature/node_modules/jsprim/lib/jsprim.js 81636568: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/package.json 81632804: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf/lib/extsprintf.js 81801412: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/package.json 81797823: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/lib/verror.js 81774451: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/package.json 81763963: node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema/lib/validate.js 81577777: node_modules/request/node_modules/http-signature/lib/verify.js 82533240: node_modules/request/node_modules/mime-types/package.json 82371286: node_modules/request/node_modules/mime-types/index.js 82530646: node_modules/request/node_modules/mime-types/node_modules/mime-db/package.json 82530510: node_modules/request/node_modules/mime-types/node_modules/mime-db/index.js 82387545: node_modules/request/node_modules/mime-types/node_modules/mime-db/db.json 82606571: node_modules/request/node_modules/stringstream/package.json 82607891: node_modules/request/node_modules/stringstream/stringstream.js 80756086: node_modules/request/node_modules/caseless/package.json 80754327: node_modules/request/node_modules/caseless/index.js 80805500: node_modules/request/node_modules/forever-agent/package.json 80801324: node_modules/request/node_modules/forever-agent/index.js 80986121: node_modules/request/node_modules/form-data/package.json 80814876: node_modules/request/node_modules/form-data/lib/form_data.js 80777465: node_modules/request/node_modules/combined-stream/package.json 80764215: node_modules/request/node_modules/combined-stream/lib/combined_stream.js 80775847: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/package.json 80773528: node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js 80983078: node_modules/request/node_modules/form-data/node_modules/async/package.json 80944514: node_modules/request/node_modules/form-data/node_modules/async/lib/async.js 80826033: node_modules/request/node_modules/form-data/lib/populate.js 82349146: node_modules/request/node_modules/isstream/package.json 82348558: node_modules/request/node_modules/isstream/isstream.js 82342515: node_modules/request/node_modules/is-typedarray/package.json 82341499: node_modules/request/node_modules/is-typedarray/index.js 4479214: node_modules/request/lib/getProxyFromURI.js 4481482: node_modules/request/lib/querystring.js 82601463: node_modules/request/node_modules/qs/package.json 82587962: node_modules/request/node_modules/qs/lib/index.js 82593363: node_modules/request/node_modules/qs/lib/stringify.js 82597342: node_modules/request/node_modules/qs/lib/utils.js 82588115: node_modules/request/node_modules/qs/lib/parse.js 4482815: node_modules/request/lib/har.js 81178912: node_modules/request/node_modules/har-validator/package.json 81001381: node_modules/request/node_modules/har-validator/lib/index.js 81176502: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/package.json 81163939: node_modules/request/node_modules/har-validator/node_modules/pinkie-promise/index.js 81001935: node_modules/request/node_modules/har-validator/lib/runner.js 81005359: node_modules/request/node_modules/har-validator/lib/schemas/index.js 81002525: node_modules/request/node_modules/har-validator/lib/schemas/cache.json 81002712: node_modules/request/node_modules/har-validator/lib/schemas/cacheEntry.json 81003206: node_modules/request/node_modules/har-validator/lib/schemas/content.json 81003583: node_modules/request/node_modules/har-validator/lib/schemas/cookie.json 81004081: node_modules/request/node_modules/har-validator/lib/schemas/creator.json 81004311: node_modules/request/node_modules/har-validator/lib/schemas/entry.json 81005242: node_modules/request/node_modules/har-validator/lib/schemas/har.json 81007111: node_modules/request/node_modules/har-validator/lib/schemas/log.json 81007604: node_modules/request/node_modules/har-validator/lib/schemas/page.json 81008181: node_modules/request/node_modules/har-validator/lib/schemas/pageTimings.json 81008406: node_modules/request/node_modules/har-validator/lib/schemas/postData.json 81009060: node_modules/request/node_modules/har-validator/lib/schemas/record.json 81009286: node_modules/request/node_modules/har-validator/lib/schemas/request.json 81010139: node_modules/request/node_modules/har-validator/lib/schemas/response.json 81010946: node_modules/request/node_modules/har-validator/lib/schemas/timings.json 81001195: node_modules/request/node_modules/har-validator/lib/error.js 81161590: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/package.json 81108729: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/index.js 81147021: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/package.json 81132607: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/index.js 81145615: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/package.json 81134601: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-object-property/node_modules/is-property/is-property.js 81128902: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/package.json 81127606: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/generate-function/index.js 81151111: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/package.json 81149530: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/jsonpointer/jsonpointer.js 81158029: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/xtend/package.json 81157276: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/node_modules/xtend/immutable.js 81106380: node_modules/request/node_modules/har-validator/node_modules/is-my-json-valid/formats.js 4533728: node_modules/request/lib/auth.js 1962761: node_modules/node-uuid/package.json 1964629: node_modules/node-uuid/uuid.js 4550226: node_modules/request/lib/oauth.js 82548387: node_modules/request/node_modules/oauth-sign/package.json 82544802: node_modules/request/node_modules/oauth-sign/index.js 4568756: node_modules/request/lib/multipart.js 4585628: node_modules/request/lib/redirect.js 4594531: node_modules/request/lib/tunnel.js 82856379: node_modules/request/node_modules/tunnel-agent/package.json 82849535: node_modules/request/node_modules/tunnel-agent/index.js ================================================ FILE: packages/client-app/build/resources/linux/debian/control.in ================================================ Package: <%= name %> Version: <%= version %> Depends: libgnome-keyring0, gir1.2-gnomekeyring-1.0, git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils Section: <%= section %> Priority: optional Architecture: <%= arch %> Installed-Size: <%= installedSize %> Maintainer: <%= maintainer %> Description: <%= description %> <%= description %> ================================================ FILE: packages/client-app/build/resources/linux/debian/lintian-overrides ================================================ nylas: arch-dependent-file-in-usr-share nylas: changelog-file-missing-in-native-package nylas: copyright-file-contains-full-apache-2-license nylas: copyright-should-refer-to-common-license-file-for-apache-2 nylas: copyright-should-refer-to-common-license-file-for-lgpl nylas: embedded-library nylas: package-installs-python-bytecode nylas: unstripped-binary-or-object nylas: extra-license-file ================================================ FILE: packages/client-app/build/resources/linux/debian/postinst ================================================ #!/bin/sh # postinst script for Nylas # # see: dh_installdeb(1) # summary of how this script can be called: # * `configure' # * abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-remove' # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package UBUNTU_CODENAMES="precise trusty utopic vivid" # "xenial is not yet available in nylas repos." DEBIAN_CODENAMES="squeeze wheezy jessie sid" case "$1" in configure) gtk-update-icon-cache /usr/share/icons/hicolor > /dev/null 2>&1 DISTRO=`lsb_release -s -i` if [ "$DISTRO" = "Ubuntu" ] || [ "$DISTRO" = "elementary OS" ] || [ "$DISTRO" = "LinuxMint" ] ; then DISTS=$UBUNTU_CODENAMES DISTRO="ubuntu" elif [ "$DISTRO" = "Debian" ]; then DISTS=$DEBIAN_CODENAMES DISTRO="debian" else echo "You are not running Debian, Ubuntu, ElementaryOS or LinuxMint. Not adding Nylas repository." DISTRO="" fi if [ -n "$DISTRO" ]; then # Add the Nylas repository. # Copyright (c) 2009 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license. # Install the repository signing key install_key() { APT_KEY="`which apt-key 2> /dev/null`" if [ -x "$APT_KEY" ]; then "$APT_KEY" add - >/dev/null 2>&1 </dev/null | cut -d ':' -f 1) if [ -n "$SOURCELIST" ]; then return 0 fi printf "$REPOCONFIG\n" > "$APT_SOURCESDIR/nylas.list" if [ $? -eq 0 ]; then return 1 fi fi return 2 } install_key update_sources_lists fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument '$1'" >&2 exit 1 ;; esac set -e exit 0 ================================================ FILE: packages/client-app/build/resources/linux/debian/postrm ================================================ #!/bin/sh # Remove the Nylas repository. # Copyright (c) 2009 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license. set -e action="$1" # Only do complete clean-up on purge. if [ "$action" != "purge" ] ; then exit 0 fi APT_GET="`which apt-get 2> /dev/null`" APT_CONFIG="`which apt-config 2> /dev/null`" # Parse apt configuration and return requested variable value. apt_config_val() { APTVAR="$1" if [ -x "$APT_CONFIG" ]; then "$APT_CONFIG" dump | sed -e "/^$APTVAR /"'!d' -e "s/^$APTVAR \"\(.*\)\".*/\1/" fi } uninstall_key() { APT_KEY="`which apt-key 2> /dev/null`" if [ -x "$APT_KEY" ]; then # don't fail if the key wasn't found "$APT_KEY" rm 7D0ACF4A >/dev/null 2>&1 || true fi } # Set variables for the locations of the apt sources lists. find_apt_sources() { APTDIR=$(apt_config_val Dir) APTETC=$(apt_config_val 'Dir::Etc') APT_SOURCES="$APTDIR$APTETC$(apt_config_val 'Dir::Etc::sourcelist')" APT_SOURCESDIR="$APTDIR$APTETC$(apt_config_val 'Dir::Etc::sourceparts')" } # Remove a repository from the apt sources. # Returns: # 0 - successfully removed, or not configured # 1 - failed to remove clean_sources_lists() { find_apt_sources if [ -d "$APT_SOURCESDIR" ]; then rm -f "$APT_SOURCESDIR/nylas.list" fi return 0 } uninstall_key clean_sources_lists exit 0 ================================================ FILE: packages/client-app/build/resources/linux/nylas-mail.desktop.in ================================================ [Desktop Entry] Name=<%= productName %> Comment=<%= description %> GenericName=<%= productName %> Exec=/usr/bin/nylas-mail %U Icon=nylas-mail Type=Application StartupNotify=true StartupWMClass=<%= productName %> Categories=GNOME;GTK;Network;Email;Utility;Development; MimeType=text/plain;x-scheme-handler/mailto;x-scheme-handler/nylas; ================================================ FILE: packages/client-app/build/resources/linux/redhat/nylas.spec.in ================================================ Name: <%= name %> Version: <%= version %> Release: 0.1%{?dist} Summary: <%= description %> License: GPLv3 URL: https://github.com/nylas/nylas-mail AutoReqProv: no # Avoid libchromiumcontent.so missing dependency requires: libgnome-keyring %description <%= description %> %install mkdir -p %{buildroot}/usr/share/nylas-mail cp -r <%= contentsDir %>/* %{buildroot}/usr/share/nylas-mail mkdir -p %{buildroot}/usr/bin/ ln -s ../share/nylas-mail/nylas %{buildroot}/usr/bin/nylas-mail chmod 755 %{buildroot}/usr/bin/nylas-mail mkdir -p %{buildroot}/usr/share/applications/ mv nylas-mail.desktop %{buildroot}/usr/share/applications/ for s in 16 32 64 128 256 512; do mkdir -p %{buildroot}/usr/share/icons/hicolor/${s}x${s}/apps cp -p <%= linuxAssetsDir %>/icons/${s}.png %{buildroot}/usr/share/icons/hicolor/${s}x${s}/apps/nylas-mail.png done %files /usr/bin/nylas-mail /usr/share/nylas-mail /usr/share/applications/nylas-mail.desktop /usr/share/icons/hicolor/16x16/apps/nylas-mail.png /usr/share/icons/hicolor/32x32/apps/nylas-mail.png /usr/share/icons/hicolor/64x64/apps/nylas-mail.png /usr/share/icons/hicolor/128x128/apps/nylas-mail.png /usr/share/icons/hicolor/256x256/apps/nylas-mail.png /usr/share/icons/hicolor/512x512/apps/nylas-mail.png ================================================ FILE: packages/client-app/build/resources/mac/Nylas Calendar.app/Contents/Info.plist ================================================ BuildMachineOSBuild 15E65 CFBundleDevelopmentRegion en CFBundleExecutable Nylas Calendar CFBundleIconFile AppIcon CFBundleIdentifier com.nylas.Nylas-Calendar CFBundleInfoDictionaryVersion 6.0 CFBundleName Nylas Calendar CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleSupportedPlatforms MacOSX CFBundleURLTypes CFBundleURLName nylas-calendar-shim CFBundleVersion 1 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild 7D1014 DTPlatformVersion GM DTSDKBuild 15E60 DTSDKName macosx10.11 DTXcode 0731 DTXcodeBuild 7D1014 LSMinimumSystemVersion 10.11 NSHumanReadableCopyright Copyright © 2016 Ben Gotow. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: packages/client-app/build/resources/mac/Nylas Calendar.app/Contents/PkgInfo ================================================ APPL???? ================================================ FILE: packages/client-app/build/resources/mac/Nylas Calendar.app/Contents/_CodeSignature/CodeResources ================================================ files Resources/AppIcon.icns 5v+SAI+weVs8VSrknYJvITKSEws= Resources/Base.lproj/MainMenu.nib hash 3K0ICUQtN1fqxnQ0VFIIBLmDg00= optional files2 Resources/AppIcon.icns hash 5v+SAI+weVs8VSrknYJvITKSEws= hash2 cDmR/kt31C8E2IvUvGZRLOTDSOnZAtRnMPhGIJs6k00= Resources/Base.lproj/MainMenu.nib hash 3K0ICUQtN1fqxnQ0VFIIBLmDg00= hash2 v9hB8Bi1UaRdestGh/P5TKwS9ntchvYPnE+TZp/y76w= optional rules ^Resources/ ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^version.plist$ rules2 .*\.dSYM($|/) weight 11 ^(.*/)?\.DS_Store$ omit weight 2000 ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ nested weight 10 ^.* ^Info\.plist$ omit weight 20 ^PkgInfo$ omit weight 20 ^Resources/ weight 20 ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^[^/]+$ nested weight 10 ^embedded\.provisionprofile$ weight 20 ^version\.plist$ weight 20 ================================================ FILE: packages/client-app/build/resources/mac/nylas-Info.plist ================================================ NSPrincipalClass AtomApplication CFBundleDocumentTypes LSHandlerRank Alternate CFBundleTypeRole Viewer CFBundleTypeName File CFBundleTypeExtensions * ================================================ FILE: packages/client-app/build/resources/win/elevate.cmd ================================================ @setlocal @echo off set CMD=%* set APP=%1 start wscript //nologo "%~dpn0.vbs" %* ================================================ FILE: packages/client-app/build/resources/win/elevate.vbs ================================================ Set Shell = CreateObject("Shell.Application") Set WShell = WScript.CreateObject("WScript.Shell") Set ProcEnv = WShell.Environment("PROCESS") cmd = ProcEnv("CMD") app = ProcEnv("APP") args= Right(cmd,(Len(cmd)-Len(app))) If (WScript.Arguments.Count >= 1) Then Shell.ShellExecute app, args, "", "runas", 0 Else WScript.Quit End If ================================================ FILE: packages/client-app/build/resources/win/nylas-mailto-registration.reg ================================================ Windows Registry Editor Version 5.00 [{{HKEY_ROOT}}\SOFTWARE\Classes\Nylas.Url.mailto] "FriendlyTypeName"="Nylas Url" [{{HKEY_ROOT}}\SOFTWARE\Classes\Nylas.Url.mailto\shell] [{{HKEY_ROOT}}\SOFTWARE\Classes\Nylas.Url.mailto\shell\open] [{{HKEY_ROOT}}\SOFTWARE\Classes\Nylas.Url.mailto\shell\open\command] @="\"{{PATH_TO_ROOT_FOLDER}}\\Update.exe\" --processStart nylas.exe --process-start-args %1" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas] @="Nylas" "LocalizedString"="@{{PATH_TO_ROOT_FOLDER}}\\Update.exe,-123" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\DefaultIcon] @="{{PATH_TO_APP_FOLDER}}\\nylas.exe,1" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Capabilities] "ApplicationName"="Nylas Mail" "ApplicationDescription"="A fast, modern mail client designed to help you boost your productivity." [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Capabilities\StartMenu] "Mail"="Nylas" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Capabilities\URLAssociations] "mailto"="Nylas.Url.mailto" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols] [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols\mailto] @="URL:MailTo Protocol" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols\mailto\DefaultIcon] @="{{PATH_TO_APP_FOLDER}}\\nylas.exe,1" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols\mailto\shell] [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols\mailto\shell\open] [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\Protocols\mailto\shell\open\command] @="\"{{PATH_TO_ROOT_FOLDER}}\\Update.exe\" --processStart nylas.exe --process-start-args %1" [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\shell] [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\shell\open] [{{HKEY_ROOT}}\SOFTWARE\Clients\Mail\Nylas\shell\open\command] @="\"{{PATH_TO_ROOT_FOLDER}}\\Update.exe\" --processStart nylas.exe" [{{HKEY_ROOT}}\SOFTWARE\RegisteredApplications] "Nylas"="Software\\Clients\\Mail\\Nylas\\Capabilities" [HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache] "{{PATH_TO_ROOT_FOLDER}}\\Update.exe"="Nylas Mail" "{{PATH_TO_ROOT_FOLDER}}\\Update.exe.FriendlyAppName"="Nylas Mail" "{{PATH_TO_ROOT_FOLDER}}\\Update.exe.ApplicationCompany"="Nylas" ================================================ FILE: packages/client-app/build/tasks/coffeelint-task.js ================================================ module.exports = (grunt) => { grunt.config.merge({ coffeelint: { 'options': { configFile: 'build/config/coffeelint.json', }, 'src': grunt.config('source:coffeescript'), 'build': [ 'build/tasks/**/*.coffee', ], 'test': [ 'spec/**/*.cjsx', 'spec/**/*.coffee', ], 'static': [ 'static/**/*.coffee', 'static/**/*.cjsx', ], 'target': (grunt.option("target") ? grunt.option("target").split(" ") : []), }, }); grunt.loadNpmTasks('grunt-contrib-coffee'); grunt.loadNpmTasks('grunt-coffeelint-cjsx'); } ================================================ FILE: packages/client-app/build/tasks/create-mac-dmg.js ================================================ const path = require('path'); const createDMG = require('electron-installer-dmg') module.exports = (grunt) => { grunt.registerTask('create-mac-dmg', 'Create DMG for Nylas Mail', function pack() { const done = this.async(); const dmgPath = path.join(grunt.config('outputDir'), "NylasMail.dmg"); createDMG({ appPath: path.join(grunt.config('outputDir'), "Nylas Mail-darwin-x64", "Nylas Mail.app"), name: "NylasMail", background: path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'Nylas-Mail-DMG-background.png'), icon: path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'nylas.icns'), overwrite: true, out: grunt.config('outputDir'), }, (err) => { if (err) { done(err); return } grunt.log.writeln(`>> Created ${dmgPath}`); done(null); }) }); }; ================================================ FILE: packages/client-app/build/tasks/create-mac-zip.js ================================================ /* eslint prefer-template: 0 */ /* eslint global-require: 0 */ /* eslint quote-props: 0 */ const path = require('path'); module.exports = (grunt) => { const {spawn} = grunt.config('taskHelpers') grunt.registerTask('create-mac-zip', 'Zip up Nylas Mail', function pack() { const done = this.async(); const zipPath = path.join(grunt.config('outputDir'), 'NylasMail.zip'); if (grunt.file.exists(zipPath)) { grunt.file.delete(zipPath, {force: true}); } const orig = process.cwd(); process.chdir(path.join(grunt.config('outputDir'), 'Nylas Mail-darwin-x64')); spawn({ cmd: "zip", args: ["-9", "-y", "-r", "-9", "-X", zipPath, 'Nylas Mail.app'], }, (error) => { process.chdir(orig); if (error) { done(error); return; } grunt.log.writeln(`>> Created ${zipPath}`); done(null); }); }); }; ================================================ FILE: packages/client-app/build/tasks/csslint-task.js ================================================ module.exports = (grunt) => { grunt.config.merge({ csslint: { options: { 'adjoining-classes': false, 'duplicate-background-images': false, 'box-model': false, 'box-sizing': false, 'bulletproof-font-face': false, 'compatible-vendor-prefixes': false, 'display-property-grouping': false, 'fallback-colors': false, 'font-sizes': false, 'gradients': false, 'ids': false, 'important': false, 'known-properties': false, 'outline-none': false, 'overqualified-elements': false, 'qualified-headings': false, 'unique-headings': false, 'universal-selector': false, 'vendor-prefix': false, 'duplicate-properties': false, // doesn't place nice with mixins }, src: [ 'static/**/*.css', ], }, }); grunt.loadNpmTasks('grunt-contrib-csslint'); } ================================================ FILE: packages/client-app/build/tasks/docs-build-task.js ================================================ const path = require('path'); const cjsxtransform = require('coffee-react-transform'); const rimraf = require('rimraf'); const fs = require('fs-plus'); var fs_extra = require('fs-extra'); const _ = require('underscore'); const donna = require('donna'); const joanna = require('joanna'); const tello = require('tello'); module.exports = function(grunt) { let {cp, mkdir, rm} = grunt.config('taskHelpers'); let getClassesToInclude = function() { let modulesPath = path.resolve(__dirname, '..', '..', 'internal_packages'); let classes = {}; fs.traverseTreeSync(modulesPath, function(modulePath) { // Don't traverse inside dependencies if (modulePath.match(/node_modules/g)) { return false; } // Don't traverse blacklisted packages (that have docs, but we don't want to include) if (path.basename(modulePath) !== 'package.json') { return true; } if (!fs.isFileSync(modulePath)) { return true; } let apiPath = path.join(path.dirname(modulePath), 'api.json'); if (fs.isFileSync(apiPath)) { _.extend(classes, grunt.file.readJSON(apiPath).classes); } return true; }); return classes; }; let sortClasses = function(classes) { let sortedClasses = {}; for (let className of Array.from(Object.keys(classes).sort())) { sortedClasses[className] = classes[className]; } return sortedClasses; }; return grunt.registerTask('docs-build', 'Builds the API docs in src', function() { grunt.log.writeln("Time to build the docs!") let done = this.async(); let classDocsOutputDir = grunt.config.get('classDocsOutputDir'); let cjsxOutputDir = path.join(classDocsOutputDir, 'temp-cjsx'); return rimraf(cjsxOutputDir, function() { let api; fs.mkdir(cjsxOutputDir); let srcPath = path.resolve(__dirname, '..', '..', 'src'); const blacklist = ['/K2/', 'legacy-edgehill-api', 'edgehill-api']; let in_blacklist = function(file) { for (var i = 0; i < blacklist.length; i++) { if (file.indexOf(blacklist[i]) >= 0) { return true; } } return false; }; fs.traverseTreeSync(srcPath, function(file) { if (in_blacklist(file)) { console.log("Skipping " + file); // Skip K2 } // Convert CJSX into coffeescript that can be read by Donna else if (path.extname(file) === '.cjsx') { let transformed = cjsxtransform(grunt.file.read(file)); // Only attempt to parse this file as documentation if it contains // real Coffeescript classes. if (transformed.indexOf('\nclass ') > 0) { grunt.log.writeln("Found class in file: " + file) grunt.file.write(path.join(cjsxOutputDir, path.basename(file).slice(0, -5 + 1 || undefined)+'coffee'), transformed); } } else if (path.extname(file) === '.jsx') { console.log('Transforming ' + file) let fileStr = grunt.file.read(file); let transformed = require("babel-core").transform(fileStr, { plugins: ["transform-react-jsx", "transform-class-properties"], presets: ['react', 'stage-2'] }); grunt.file.write(path.join(cjsxOutputDir, path.basename(file).slice(0, -3 || undefined)+'js'), transformed.code); } else if (path.extname(file) == '.es6') { console.log(file); let fileStr = grunt.file.read(file); let transformed = require("babel-core").transform(fileStr, { plugins: ["transform-class-properties", "transform-function-bind"], presets: ['react', 'stage-2'] }); if (transformed.code.indexOf('class ') > 0) { grunt.log.writeln("Found class in file: " + file) grunt.file.write(path.join(cjsxOutputDir, path.basename(file).slice(0, -3 || undefined)+'js'), transformed.code); } } else if (path.extname(file) == '.coffee' || path.extname(file) == '.js') { let dest_path = path.join(cjsxOutputDir, path.basename(file)); console.log("Copying " + file + " to " + dest_path); fs_extra.copySync(file, dest_path); } return true; }); grunt.log.ok('Done transforming, starting donna extraction') grunt.log.writeln('cjsxOutputDir: ' + cjsxOutputDir) // Process coffeescript source let metadata = donna.generateMetadata([cjsxOutputDir]); grunt.log.ok('---- Done with Donna (cjsx metadata)----'); // DEBUG // Use to check individual files var js_files = [] fs.traverseTreeSync(cjsxOutputDir, function(file) { if (path.extname(file) === '.js') { console.log('testing joanna on ' + file) let meta = joanna([file]) console.log('testing tello on ' + file) tello.digest(meta) console.log('passed') } }); var js_files = [] fs.traverseTreeSync(cjsxOutputDir, function(file) { if (path.extname(file) === '.js') { js_files.push(file.toString()) } }); console.log(js_files); grunt.log.ok('---- Starting Jonna (jsx metadata)----'); let jsx_metadata = joanna(js_files); grunt.log.ok('---- Done with Joanna (jsx metadata)----'); Object.assign(metadata[0].files, jsx_metadata.files); console.log(metadata[0]); grunt.file.write('/tmp/metadata.json', JSON.stringify(metadata, null, 2)); try { api = tello.digest(metadata); } catch (e) { console.log(e) console.log(e.stack); console.log(metadata) return; } console.log('---- Done with Tello ----'); _.extend(api.classes, getClassesToInclude()); console.log(api.classes) api.classes = sortClasses(api.classes); console.log(api.classes) let apiJson = JSON.stringify(api, null, 2); let apiJsonPath = path.join(classDocsOutputDir, 'api.json'); grunt.file.write(apiJsonPath, apiJson); return done(); }); }); }; ================================================ FILE: packages/client-app/build/tasks/docs-render-task.js ================================================ const path = require('path'); const Handlebars = require('handlebars'); const marked = require('meta-marked'); const fs = require('fs-plus'); const _ = require('underscore'); marked.setOptions({ highlight(code) { return require('highlight.js').highlightAuto(code).value; } }); let standardClassURLRoot = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/'; let standardClasses = [ 'string', 'object', 'array', 'function', 'number', 'date', 'error', 'boolean', 'null', 'undefined', 'json', 'set', 'map', 'typeerror', 'syntaxerror', 'referenceerror', 'rangeerror' ]; let thirdPartyClasses = { 'react.component': 'https://facebook.github.io/react/docs/component-api.html', 'promise': 'https://github.com/petkaantonov/bluebird/blob/master/API.md', 'range': 'https://developer.mozilla.org/en-US/docs/Web/API/Range', 'selection': 'https://developer.mozilla.org/en-US/docs/Web/API/Selection', 'node': 'https://developer.mozilla.org/en-US/docs/Web/API/Node', }; module.exports = function(grunt) { let {cp, mkdir, rm} = grunt.config('taskHelpers'); let relativePathForClass = classname => classname+'.html'; let outputPathFor = function(relativePath) { let classDocsOutputDir = grunt.config.get('classDocsOutputDir'); return path.join(classDocsOutputDir, relativePath); }; var processFields = function(json, fields, tasks) { let val; if (fields == null) { fields = []; } if (tasks == null) { tasks = []; } if (json instanceof Array) { return (() => { let result = []; for (val of Array.from(json)) { result.push(processFields(val, fields, tasks)); } return result; })(); } else { return (() => { let result1 = []; for (let key in json) { val = json[key]; let item; if (Array.from(fields).includes(key)) { for (let task of Array.from(tasks)) { val = task(val); } json[key] = val; } if (_.isObject(val)) { item = processFields(val, fields, tasks); } result1.push(item); } return result1; })(); } }; return grunt.registerTask('docs-render', 'Builds html from the API docs', function() { let documentation, filename, html, match, meta, name, result, section, val; let classDocsOutputDir = grunt.config.get('classDocsOutputDir'); // Parse API reference Markdown let classes = []; let apiJsonPath = path.join(classDocsOutputDir, 'api.json'); let apiJSON = JSON.parse(grunt.file.read(apiJsonPath)); for (var classname in apiJSON.classes) { // Parse a "@Section" out of the description if one is present let contents = apiJSON.classes[classname]; let sectionRegex = /Section: ?([\w ]*)(?:$|\n)/; section = 'General'; match = sectionRegex.exec(contents.description); if (match) { contents.description = contents.description.replace(match[0], ''); section = match[1].trim(); } // Replace superClass "React" with "React.Component". The Coffeescript Lexer // is so bad. if (contents.superClass === "React") { contents.superClass = "React.Component"; } classes.push({ name: classname, documentation: contents, section }); } // Build Sidebar metadata we can hand off to each of the templates to // generate the sidebar let sidebar = {}; for (var i = 0; i < classes.length; i++) { var current_class = classes[i]; console.log(current_class.name + ' ' + current_class.section) if (!(current_class.section in sidebar)) { sidebar[current_class.section] = [] } sidebar[current_class.section].push(current_class.name) } // Prepare to render by loading handlebars partials let templatesPath = path.resolve(grunt.config('buildDir'), 'docs_templates'); grunt.file.recurse(templatesPath, function(abspath, root, subdir, filename) { if ((filename[0] === '_') && (path.extname(filename) === '.html')) { return Handlebars.registerPartial(filename, grunt.file.read(abspath)); } }); // Render Helpers let knownClassnames = {}; for (classname in apiJSON.classes) { val = apiJSON.classes[classname]; knownClassnames[classname.toLowerCase()] = val; } let expandTypeReferences = function(val) { let refRegex = /{([\w.]*)}/g; while ((match = refRegex.exec(val)) !== null) { let term = match[1].toLowerCase(); let label = match[1]; let url = false; if (Array.from(standardClasses).includes(term)) { url = standardClassURLRoot+term; } else if (thirdPartyClasses[term]) { url = thirdPartyClasses[term]; } else if (knownClassnames[term]) { url = relativePathForClass(knownClassnames[term].name); grunt.log.ok("Found: " + term) } else { console.warn(`Cannot find class named ${term}`); } if (url) { val = val.replace(match[0], `${label}`); } } return val; }; let expandFuncReferences = function(val) { let refRegex = /{([\w]*)?::([\w]*)}/g; while ((match = refRegex.exec(val)) !== null) { var label; let [text, a, b] = Array.from(match); let url = false; if (a && b) { url = `${relativePathForClass(a)}#${b}`; label = `${a}::${b}`; } else { url = `#${b}`; label = `${b}`; } if (url) { val = val.replace(text, `${label}`); } } return val; }; // DEBUG Render sidebar json // grunt.file.write(outputPathFor('sidebar.json'), JSON.stringify(sidebar, null, 2)); // Render Class Pages let classTemplatePath = path.join(templatesPath, 'class.md'); let classTemplate = Handlebars.compile(grunt.file.read(classTemplatePath)); for ({name, documentation, section} of Array.from(classes)) { // Recursively process `description` and `type` fields to process markdown, // expand references to types, functions and other files. processFields(documentation, ['description'], [expandFuncReferences]); processFields(documentation, ['type'], [expandTypeReferences]); result = classTemplate({name, documentation, section}); grunt.file.write(outputPathFor(name + '.md'), result); } let sidebarTemplatePath = path.join(templatesPath, 'sidebar.md'); let sidebarTemplate = Handlebars.compile(grunt.file.read(sidebarTemplatePath)); grunt.file.write(outputPathFor('Sidebar.md'), sidebarTemplate({sidebar})); // Remove temp cjsx output return fs.removeSync(outputPathFor("temp-cjsx")); }); }; function __guard__(value, transform) { return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; } ================================================ FILE: packages/client-app/build/tasks/docs-task.js ================================================ const path = require('path'); const cjsxtransform = require('coffee-react-transform'); const rimraf = require('rimraf'); const fs = require('fs-plus'); const _ = require('underscore'); const donna = require('donna'); const joanna = require('joanna'); const tello = require('tello'); module.exports = function(grunt) { let {cp, mkdir, rm} = grunt.config('taskHelpers'); let getClassesToInclude = function() { let modulesPath = path.join(grunt.config('appDir'), 'internal_packages'); let classes = {}; fs.traverseTreeSync(modulesPath, function(modulePath) { // Don't traverse inside dependencies if (modulePath.match(/node_modules/g)) { return false; } // Don't traverse blacklisted packages (that have docs, but we don't want to include) if (path.basename(modulePath) !== 'package.json') { return true; } if (!fs.isFileSync(modulePath)) { return true; } let apiPath = path.join(path.dirname(modulePath), 'api.json'); if (fs.isFileSync(apiPath)) { _.extend(classes, grunt.file.readJSON(apiPath).classes); } return true; }); return classes; }; let sortClasses = function(classes) { let sortedClasses = {}; for (let className of Array.from(Object.keys(classes).sort())) { sortedClasses[className] = classes[className]; } return sortedClasses; }; var processFields = function(json, fields, tasks) { let val; if (fields == null) { fields = []; } if (tasks == null) { tasks = []; } if (json instanceof Array) { return (() => { let result = []; for (val of Array.from(json)) { result.push(processFields(val, fields, tasks)); } return result; })(); } else { return (() => { let result1 = []; for (let key in json) { val = json[key]; let item; if (Array.from(fields).includes(key)) { for (let task of Array.from(tasks)) { val = task(val); } json[key] = val; } if (_.isObject(val)) { item = processFields(val, fields, tasks); } result1.push(item); } return result1; })(); } }; return grunt.registerTask('docs', 'Builds the API docs in src', function() { grunt.log.writeln("Time to build the docs!") let done = this.async(); // Convert CJSX into coffeescript that can be read by Donna // let classDocsOutputDir = grunt.config.get('classDocsOutputDir'); let classDocsOutputDir = '~/Desktop/Nylas Mail Docs/' let cjsxOutputDir = path.join(classDocsOutputDir, 'temp-cjsx'); return rimraf(cjsxOutputDir, function() { let api; fs.mkdir(cjsxOutputDir); let srcPath = path.resolve(grunt.config('appDir'), 'src'); fs.traverseTreeSync(srcPath, function(file) { if (file.indexOf('/K2/') > 0) { // Skip K2 } else if (path.extname(file) === '.cjsx') { // Should also look for jsx and es6 let transformed = cjsxtransform(grunt.file.read(file)); // Only attempt to parse this file as documentation if it contains // real Coffeescript classes. if (transformed.indexOf('\nclass ') > 0) { grunt.log.writeln("Found class in file: " + file) grunt.file.write(path.join(cjsxOutputDir, path.basename(file).slice(0, -5 + 1 || undefined)+'coffee'), transformed); } } else if (path.extname(file) === '.jsx') { console.log('Transforming ' + file) let fileStr = grunt.file.read(file); let transformed = require("babel-core").transform(fileStr, { plugins: ["transform-react-jsx", "transform-class-properties"], presets: ['react', 'stage-2'] }); if (transformed.code.indexOf('class ') > 0) { grunt.log.writeln("Found class in file: " + file) grunt.file.write(path.join(cjsxOutputDir, path.basename(file).slice(0, -3 || undefined)+'js'), transformed.code); } } return true; }); grunt.log.ok('Done transforming, starting donna extraction') grunt.log.writeln('cjsxOutputDir: ' + cjsxOutputDir) // Process coffeescript source let metadata = donna.generateMetadata([cjsxOutputDir]); grunt.log.ok('---- Done with Donna (cjsx metadata)----'); console.log(js_files); var js_files = [] fs.traverseTreeSync(cjsxOutputDir, function(file) { if (path.extname(file) === '.js') { js_files.push(file.toString()) } }); console.log(js_files); let jsx_metadata = joanna(js_files); grunt.log.ok('---- Done with Joanna (jsx metadata)----'); Object.assign(metadata, jsx_metadata); console.log(metadata); try { api = tello.digest(metadata); } catch (e) { console.log(e.stack); } console.log('---- Done with Tello ----'); _.extend(api.classes, getClassesToInclude()); api.classes = sortClasses(api.classes); let apiJson = JSON.stringify(api, null, 2); let apiJsonPath = path.join(classDocsOutputDir, 'api.json'); grunt.file.write(apiJsonPath, apiJson); return done(); }); }); }; ================================================ FILE: packages/client-app/build/tasks/eslint-task.js ================================================ const chalk = require('chalk'); const eslint = require('eslint'); module.exports = (grunt) => { grunt.config.merge({ eslint: { options: { ignore: false, configFile: '../../.eslintrc', }, target: grunt.config('source:es6'), }, eslintFixer: { src: grunt.config('source:es6'), }, }); grunt.registerMultiTask('eslint', 'Validate files with ESLint', function task() { const opts = this.options({ outputFile: false, quiet: false, maxWarnings: -1, }); if (this.filesSrc.length === 0) { grunt.log.writeln(chalk.magenta('Could not find any files to validate.')); return true; } const formatter = eslint.CLIEngine.getFormatter(opts.format); if (!formatter) { grunt.warn(`Could not find formatter ${opts.format}.`); return false; } const engine = new eslint.CLIEngine(opts); let report = null; try { report = engine.executeOnFiles(this.filesSrc); } catch (err) { grunt.warn(err); return false; } if (opts.fix) { eslint.CLIEngine.outputFixes(report); } let results = report.results; if (opts.quiet) { results = eslint.CLIEngine.getErrorResults(results); } const output = formatter(results); if (opts.outputFile) { grunt.file.write(opts.outputFile, output); } else if (output) { console.log(output); } const tooManyWarnings = opts.maxWarnings >= 0 && report.warningCount > opts.maxWarnings; if (report.errorCount === 0 && tooManyWarnings) { grunt.warn(`ESLint found too many warnings (maximum:${opts.maxWarnings})`); } return report.errorCount === 0; }); }; ================================================ FILE: packages/client-app/build/tasks/installer-linux-task.js ================================================ /* eslint global-require:0 */ const fs = require('fs'); const path = require('path'); const _ = require('underscore'); module.exports = (grunt) => { const {spawn} = grunt.config('taskHelpers'); const outputDir = grunt.config.get('outputDir'); const contentsDir = path.join(grunt.config('outputDir'), `nylas-linux-${process.arch}`); const linuxAssetsDir = path.resolve(path.join(grunt.config('buildDir'), 'resources', 'linux')); const arch = { ia32: 'i386', x64: 'amd64', }[process.arch]; // a few helpers const writeFromTemplate = (filePath, data) => { const template = _.template(String(fs.readFileSync(filePath))) const finishedPath = path.join(outputDir, path.basename(filePath).replace('.in', '')); grunt.file.write(finishedPath, template(data)); return finishedPath; } const getInstalledSize = (dir, callback) => { const cmd = 'du'; const args = ['-sk', dir]; spawn({cmd, args}, (error, {stdout}) => { const installedSize = stdout.split(/\s+/).shift() || '200000'; // default to 200MB callback(null, installedSize); }); } grunt.registerTask('create-rpm-installer', 'Create rpm package', function mkrpmf() { const done = this.async() if (!arch) { done(new Error(`Unsupported arch ${process.arch}`)); return; } const rpmDir = path.join(grunt.config('outputDir'), 'rpm'); if (grunt.file.exists(rpmDir)) { grunt.file.delete(rpmDir, {force: true}); } const templateData = { name: grunt.config('appJSON').name, version: grunt.config('appJSON').version, description: grunt.config('appJSON').description, productName: grunt.config('appJSON').productName, linuxShareDir: '/usr/local/share/nylas', linuxAssetsDir: linuxAssetsDir, contentsDir: contentsDir, } // This populates nylas.spec const specInFilePath = path.join(linuxAssetsDir, 'redhat', 'nylas.spec.in') writeFromTemplate(specInFilePath, templateData) // This populates nylas.desktop const desktopInFilePath = path.join(linuxAssetsDir, 'nylas-mail.desktop.in') writeFromTemplate(desktopInFilePath, templateData) const cmd = path.join(grunt.config('appDir'), 'script', 'mkrpm') const args = [outputDir, contentsDir, linuxAssetsDir] spawn({cmd, args}, (error) => { if (error) { return done(error); } grunt.log.ok(`Created rpm package in ${rpmDir}`); return done(); }); }); grunt.registerTask('create-deb-installer', 'Create debian package', function mkdebf() { const done = this.async() if (!arch) { done(`Unsupported arch ${process.arch}`); return; } getInstalledSize(contentsDir, (error, installedSize) => { if (error) { done(error); return; } const version = grunt.config('appJSON').version; const data = { version: version, name: grunt.config('appJSON').name, description: grunt.config('appJSON').description, productName: grunt.config('appJSON').productName, linuxShareDir: '/usr/share/nylas-mail', arch: arch, section: 'devel', maintainer: 'Nylas Team', installedSize: installedSize, } writeFromTemplate(path.join(linuxAssetsDir, 'debian', 'control.in'), data) writeFromTemplate(path.join(linuxAssetsDir, 'nylas-mail.desktop.in'), data) const icon = path.join(grunt.config('appDir'), 'build', 'resources', 'nylas.png') const cmd = path.join(grunt.config('appDir'), 'script', 'mkdeb'); const args = [version, arch, icon, linuxAssetsDir, contentsDir, outputDir]; spawn({cmd, args}, (spawnError) => { if (spawnError) { return done(spawnError); } grunt.log.ok(`Created ${outputDir}/nylas-${version}-${arch}.deb`); return done() }); }); }); } ================================================ FILE: packages/client-app/build/tasks/lesslint-task.js ================================================ module.exports = (grunt) => { grunt.config.merge({ lesslint: { src: [ 'internal_packages/**/*.less', 'dot-nylas/**/*.less', 'static/**/*.less', ], options: { less: { paths: ['static', 'static/variables/'], }, imports: ['static/variables/*.less'], }, }, }); grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-lesslint'); } ================================================ FILE: packages/client-app/build/tasks/nylaslint-task.js ================================================ /* eslint no-cond-assign: 0 */ const path = require('path'); const fs = require('fs-plus'); function normalizeRequirePath(requirePath, fPath) { if (requirePath[0] === ".") { return path.normalize(path.join(path.dirname(fPath), requirePath)); } return requirePath; } module.exports = (grunt) => { grunt.config.merge({ nylaslint: { src: grunt.config('source:coffeescript').concat(grunt.config('source:es6')), }, }); grunt.registerMultiTask('nylaslint', 'Check requires for file extensions compiled away', function nylaslint() { const done = this.async(); // Enable once path errors are fixed. if (process.platform === 'win32') { done(); return; } const extensionRegex = /require ['"].*\.(coffee|cjsx|jsx|es6|es)['"]/i; for (const fileset of this.files) { grunt.log.writeln(`Nylinting ${fileset.src.length} files.`); const esExtensions = { ".es6": true, ".es": true, ".jsx": true, }; const errors = []; const esExport = {}; const esNoExport = {}; const esExportDefault = {}; // Temp TODO. Fix spec files for (const f of fileset.src) { if (!esExtensions[path.extname(f)]) { continue; } if (!/-spec/.test(f)) { continue; } const content = fs.readFileSync(f, {encoding: 'utf8'}); // https://regex101.com/r/rQ3eD0/1 // Matches only the first describe block const describeRe = /[\n]describe\(['"](.*?)['"], ?\(\) ?=> ?/m; if (describeRe.test(content)) { errors.push(`${f}: Spec has to start with function`); } } // NOTE: Comment me in if you want to fix these files. // _str = require('underscore.string') // replacer = (match, describeName) -> // fnName = _str.camelize(describeName, true) // return "\ndescribe('#{describeName}', function #{fnName}() " // newContent = content.replace(describeRe, replacer) // fs.writeFileSync(f, newContent, encoding:'utf8') // Build the list of ES6 files that export things and categorize for (const f of fileset.src) { if (!esExtensions[path.extname(f)]) { continue; } const lookupPath = `${path.dirname(f)}/${path.basename(f, path.extname(f))}`; const content = fs.readFileSync(f, {encoding: 'utf8'}); if (/module.exports\s?=\s?.+/gmi.test(content)) { if (!f.endsWith('nylas-exports.es6')) { errors.push(`${f}: Don't use module.exports in ES6`); } } if (/^export/gmi.test(content)) { if (/^export default/gmi.test(content)) { esExportDefault[lookupPath] = true; } else { esExport[lookupPath] = true; } } else { esNoExport[lookupPath] = true; } } // Now look again through all ES6 files, this time to check imports // instead of exports. for (const f of fileset.src) { let result = null; if (!esExtensions[path.extname(f)]) { continue; } const content = fs.readFileSync(f, {encoding: 'utf8'}); const importRe = /import \{.*\} from ['"](.*?)['"]/gmi; while (result = importRe.exec(content)) { for (const requirePath of result.slice(1)) { const lookupPath = normalizeRequirePath(requirePath, f); if (esExportDefault[lookupPath] || esNoExport[lookupPath]) { errors.push(`${f}: Don't destructure default export ${requirePath}`); } } } } // Now look through all coffeescript files // If they require things from ES6 files, ensure they're using the // proper syntax. for (const f of fileset.src) { let result = null; if (esExtensions[path.extname(f)]) { continue; } const content = fs.readFileSync(f, {encoding: 'utf8'}); if (extensionRegex.test(content)) { errors.push(`${f}: Remove extensions when requiring files`); } const requireRe = /require[ (]['"]([\w_./-]*?)['"]/gmi; while (result = requireRe.exec(content)) { for (const requirePath of result.slice(1)) { const lookupPath = normalizeRequirePath(requirePath, f); const baseRequirePath = path.basename(requirePath); const plainRequireRe = new RegExp(`require[ (]['"].*${baseRequirePath}['"]\\)?$`, "gm"); const defaultRequireRe = new RegExp(`require\\(['"].*${baseRequirePath}['"]\\)\\.default`, "gm"); if (esExport[lookupPath]) { if (!plainRequireRe.test(content)) { errors.push(`${f}: No \`default\` exported ${requirePath}`); } } else if (esNoExport[lookupPath]) { errors.push(`${f}: Nothing exported from ${requirePath}`); } else if (esExportDefault[lookupPath]) { if (!defaultRequireRe.test(content)) { errors.push(`${f}: Add \`default\` to require ${requirePath}`); } } else { // must be a coffeescript or core file if (defaultRequireRe.test(content)) { errors.push(`${f}: Don't ask for \`default\` from ${requirePath}`); } } } } } if (errors.length > 0) { for (const err of errors) { grunt.log.error(err); } const error = ` Please fix the #{errors.length} linter errors above. These are the issues we're looking for: ISSUES WITH COFFEESCRIPT FILES: 1. Remove extensions when requiring files: Since we compile files in production to plain ".js" files it's very important you do NOT include the file extension when "require"ing a file. 2. Add "default" to require: As of Babel 6, "require" no longer returns whatever the "default" value is. If you are "require"ing an es6 file from a coffeescript file, you must explicitly request the "default" property. For example: do "require('./my-es6-file').default" 3. Don't ask for "default": If you're requiring a coffeescript file from a coffeescript file, you will almost never need to load a "default" object. This is likely an indication you incorrectly thought you were importing an ES6 file. ISSUES WITH ES6 FILES: 4. Don't use module.exports in ES6: You sholudn't manually assign module.exports anymore. Use proper ES6 module syntax like "export default" or "export const FOO". 5. Don't destructure default export: If you're using "import {FOO} from './bar'" in ES6 files, it's important that "./bar" does NOT export a "default". Instead, in './bar', do "export const FOO = 'foo'" 6. Spec has to start with function Top-level "describe" blocks can no longer use the "() => {}" function syntax. This will incorrectly bind "this" to the "window" object instead of the jasmine object. The top-level "describe" block must use the "function describeName() {}" syntax `; done(new Error(error)); } } done(null); }); } ================================================ FILE: packages/client-app/build/tasks/package-task.js ================================================ /* eslint global-require: 0 *//* eslint prefer-template: 0 */ /* eslint quote-props: 0 */ const packager = require('electron-packager'); const path = require('path'); const util = require('util'); const tmpdir = path.resolve(require('os').tmpdir(), 'nylas-build'); const fs = require('fs-plus'); const coffeereact = require('coffee-react'); const glob = require('glob'); const babel = require('babel-core'); const symlinkedPackages = [] module.exports = (grunt) => { const packageJSON = grunt.config('appJSON'); const babelPath = path.join(grunt.config('rootDir'), '.babelrc') const babelOptions = JSON.parse(fs.readFileSync(babelPath)) function runCopyAPM(buildPath, electronVersion, platform, arch, callback) { // Move APM up out of the /app folder which will be inside the ASAR const apmTargetDir = path.resolve(buildPath, '..', 'apm'); fs.moveSync(path.join(buildPath, 'apm'), apmTargetDir) // Move /apm/node_modules/atom-package-manager up a level. We're // essentially pulling the atom-package-manager module up outside of // the node_modules folder, which is necessary because npmV3 installs // nested dependencies in the same dir. const apmPackageDir = path.join(apmTargetDir, 'node_modules', 'atom-package-manager') for (const name of fs.readdirSync(apmPackageDir)) { fs.renameSync(path.join(apmPackageDir, name), path.join(apmTargetDir, name)); } const apmSymlink = path.join(apmTargetDir, 'node_modules', '.bin', 'apm'); if (fs.existsSync(apmSymlink)) { fs.unlinkSync(apmSymlink); } fs.rmdirSync(apmPackageDir); callback(); } function runCopyPlatformSpecificResources(buildPath, electronVersion, platform, arch, callback) { // these files (like nylas-mailto-default.reg) go alongside the ASAR, // not inside it, so we need to move out of the `app` directory. const resourcesDir = path.resolve(buildPath, '..'); if (platform === 'win32') { fs.copySync(path.resolve(grunt.config('appDir'), 'build', 'resources', 'win'), resourcesDir); } callback(); } /** * We have to resolve the symlink paths (and cache the results) before * copying over the files since some symlinks may be relative paths (like * those created by lerna). We'll keep absolute references of those paths * for the symlink copy function to use after the packaging is complete. */ function resolveRealSymlinkPaths(appDir) { console.log("---> Resolving symlinks"); const dirs = [ 'internal_packages', 'src', 'spec', 'node_modules', ]; dirs.forEach((dir) => { const absoluteDir = path.join(appDir, dir); fs.readdirSync(absoluteDir).forEach((packageName) => { const relativePackageDir = path.join(dir, packageName) const absolutePackageDir = path.join(absoluteDir, packageName) const realPackagePath = fs.realpathSync(absolutePackageDir).replace('/private/', '/') if (realPackagePath !== absolutePackageDir) { console.log(` ---> Resolving '${relativePackageDir}' to '${realPackagePath}'`) symlinkedPackages.push({realPackagePath, relativePackageDir}) } }); }); } function runCopySymlinkedPackages(buildPath, electronVersion, platform, arch, callback) { console.log("---> Moving symlinked node modules / internal packages into build folder.") symlinkedPackages.forEach(({realPackagePath, relativePackageDir}) => { const packagePath = path.join(buildPath, relativePackageDir) console.log(` ---> Copying ${realPackagePath} to ${packagePath}`); fs.removeSync(packagePath); fs.copySync(realPackagePath, packagePath); }); callback(); } /** * We don't need the K2 folder anymore since the previous step hard * copied the client-sync package (and its isomorphic-core dependency) * into /internal_packages. The remains of the folder are N1-Cloud * pieces that aren't necessary */ function removeUnnecessaryFiles(buildPath, electronVersion, platform, arch, callback) { fs.removeSync(path.join(buildPath, 'src', 'K2')) callback(); } function runTranspilers(buildPath, electronVersion, platform, arch, callback) { console.log("---> Running babel and coffeescript transpilers") grunt.config('source:coffeescript').forEach(pattern => { glob.sync(pattern, {cwd: buildPath}).forEach((relPath) => { const coffeepath = path.join(buildPath, relPath) if (/(node_modules|\.js$)/.test(coffeepath)) return console.log(` ---> Compiling ${coffeepath.slice(coffeepath.indexOf("/app") + 4)}`) const outPath = coffeepath.replace(path.extname(coffeepath), '.js'); const res = coffeereact.compile(grunt.file.read(coffeepath), { bare: false, join: false, separator: grunt.util.normalizelf(grunt.util.linefeed), sourceMap: true, sourceRoot: '/', generatedFile: path.basename(outPath), sourceFiles: [path.relative(buildPath, coffeepath)], }); grunt.file.write(outPath, `${res.js}\n//# sourceMappingURL=${path.basename(outPath)}.map\n`); grunt.file.write(`${outPath}.map`, res.v3SourceMap); fs.unlinkSync(coffeepath); }); }); grunt.config('source:es6').forEach(pattern => { glob.sync(pattern, {cwd: buildPath}).forEach((relPath) => { const es6Path = path.join(buildPath, relPath) if (/(node_modules|\.js$)/.test(es6Path)) return const outPath = es6Path.replace(path.extname(es6Path), '.js'); console.log(` ---> Compiling ${es6Path.slice(es6Path.indexOf("/app") + 4)}`) const res = babel.transformFileSync(es6Path, Object.assign(babelOptions, { sourceMaps: true, sourceRoot: '/', sourceMapTarget: path.relative(buildPath, outPath), sourceFileName: path.relative(buildPath, es6Path), })); grunt.file.write(outPath, `${res.code}\n//# sourceMappingURL=${path.basename(outPath)}.map\n`); grunt.file.write(`${outPath}.map`, JSON.stringify(res.map)); fs.unlinkSync(es6Path); }); }); callback(); } const platform = grunt.option('platform'); // See: https://github.com/electron-userland/electron-packager/blob/master/usage.txt grunt.config.merge({ 'packager': { 'app-version': packageJSON.version, 'platform': platform, 'protocols': [{ name: "Nylas Protocol", schemes: ["nylas"], }, { name: "Mailto Protocol", schemes: ["mailto"], }], 'dir': grunt.config('appDir'), 'app-category-type': "public.app-category.business", 'tmpdir': tmpdir, 'arch': { 'win32': 'ia32', }[platform], 'icon': { darwin: path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'nylas.icns'), win32: path.resolve(grunt.config('appDir'), 'build', 'resources', 'win', 'nylas.ico'), linux: undefined, }[platform], 'name': { darwin: 'Nylas Mail', win32: 'nylas', linux: 'nylas', }[platform], 'app-copyright': `Copyright (C) 2014-${new Date().getFullYear()} Nylas, Inc. All rights reserved.`, 'derefSymlinks': false, 'asar': { 'unpack': "{" + [ '*.node', '**/vendor/**', 'examples/**', '**/src/tasks/**', '**/node_modules/spellchecker/**', '**/node_modules/windows-shortcuts/**', ].join(',') + "}", }, "ignore": [ // These are all relative to client-app /.*\.watchmanconfig.*/, // top level dirs we never want /^\/build.*/, /^\/dist.*/, /^\/docs.*/, /^\/docs_src.*/, /^\/script.*/, /^\/spec.*/, // general dirs we never want /[/]+gh-pages$/, /[/]+docs$/, /[/]+obj[/]+gen/, /[/]+\.deps$/, // File types we know we never want in the prod build /\.md$/i, /\.log$/i, /\.yml$/i, /\.gz/i, /\.zip/i, /\.pdb$/, /\.h$/, /\.cc$/, /\.ts$/, /\.flow$/, /\.gyp/, /\.mk/, /\.dYSM$/, // specific (large) module bits we know we don't need /node_modules[/]+less[/]+dist$/, /node_modules[/]+react[/]+dist$/, /node_modules[/].*[/]tests?$/, /node_modules[/].*[/]coverage$/, /node_modules[/].*[/]benchmark$/, /@paulbetts[/]+cld[/]+deps[/]+cld/, ], 'out': grunt.config('outputDir'), 'overwrite': true, 'prune': true, 'win32metadata': { CompanyName: 'Nylas, Inc.', FileDescription: 'Nylas Mail', LegalCopyright: `Copyright (C) 2014-${new Date().getFullYear()} Nylas, Inc. All rights reserved.`, ProductName: 'Nylas Mail', }, // NOTE: The following plist keys can NOT be set in the // nylas-Info.plist since they are manually overridden by // electron-packager based on this config file: // // CFBundleDisplayName: 'name', // CFBundleExecutable: 'name', // CFBundleIdentifier: 'app-bundle-id', // CFBundleName: 'name' // // See https://github.com/electron-userland/electron-packager/blob/master/mac.js#L50 // // Our own nylas-Info.plist gets extended on top of the // Electron.app/Contents/Info.plist. A majority of the defaults are // left in the Electron Info.plist file 'extend-info': path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'nylas-Info.plist'), 'app-bundle-id': "com.nylas.nylas-mail", 'afterCopy': [ runCopyPlatformSpecificResources, runCopyAPM, runCopySymlinkedPackages, removeUnnecessaryFiles, runTranspilers, ], }, }) grunt.registerTask('package', 'Package Nylas Mail', function pack() { const done = this.async(); const start = Date.now(); console.log('---> Running packager with options:'); console.log(util.inspect(grunt.config.get('packager'), true, 7, true)); const ongoing = setInterval(() => { const elapsed = Math.round((Date.now() - start) / 1000.0) console.log(`---> Packaging for ${elapsed}s`); }, 1000) resolveRealSymlinkPaths(grunt.config('appDir')) packager(grunt.config.get('packager'), (err, appPaths) => { clearInterval(ongoing) if (err) { grunt.fail.fatal(err); return done(err); } console.log(`---> Done Successfully. Built into: ${appPaths}`); return done(); }); }); }; ================================================ FILE: packages/client-app/build/tasks/task-helpers.js ================================================ const childProcess = require('child_process'); module.exports = (grunt) => { function spawn(options, callback) { const stdout = []; const stderr = []; let error = null; const proc = childProcess.spawn(options.cmd, options.args, options.opts); proc.stdout.on('data', data => stdout.push(data.toString())); proc.stderr.on('data', data => stderr.push(data.toString())); proc.on('error', (processError) => { return error != null ? error : (error = processError) }); proc.on('close', (exitCode, signal) => { if (exitCode !== 0) { if (typeof error === 'undefined' || error === null) { error = new Error(signal); } } const results = {stderr: stderr.join(''), stdout: stdout.join(''), code: exitCode}; if (exitCode !== 0) { grunt.log.error(results.stderr); } return callback(error, results, exitCode); }); } function spawnP(options) { return new Promise((resolve, reject) => { spawn(options, (error) => { if (error) return reject(error); return resolve() }) }) } return {spawn, spawnP}; } ================================================ FILE: packages/client-app/docs/ContinuousIntegration.md ================================================ # Building N1 with Continuous Integration script/grunt ci N1 is designed to be built into a production app for Mac, Windows, and Linux. Only Nylas core team members currently have access to produce a production build. Production builds are code-signed with a Nylas, Inc. certificate and include a handful of other proprietary assets such as custom fonts and sounds. We currently use [Travis](https://travis-ci.org/nylas/nylas-mail) to build on Mac & Windows and AppVeyor to build on Windows. A build can be run from a local machines by Jenkins or manually; however, several environment variables must be setup.: **ALL ENVIRONMENT VARIABLES ARE ENCRYPTED** They exist in an encrypted file that only Travis can read in `build/resources/certs/set_env.sh` **IMPORTANT** Do NOT remove the `2>/dev/null 1>/dev/null` in the `before_install` scripts. If any of commands fail we don't want to leak sensitive data in the output. That file must be decrypted and `source`d before the environment variables can use. If not building on Travis, the environment variables must be manually decrypted via gpg and sourced We use [Travis encryption](https://docs.travis-ci.com/user/encrypting-files/) and AppVeyor encryption to store the certificates, keys, and passwords To login to GitHub and clone the Nylas submodule with private assets you need to clone recursively (or `git submodule init; git submodule update`) with a valid SSH key or login username and password. We have a CI GitHub account: https://github.com/nylas-deploy-scripts The password for that account is stored in the environment variable: - `GITHUB_CI_ACCOUNT_PASSWORD` For signing builds on Mac only when the certificates are already in the Keychain (not Travis): - `XCODE_KEYCHAIN` - The name of the Mac keychain that contains the certificates and private key. - `XCODE_KEYCHAIN_PASSWORD` - Th password to that keychain. - `KEYCHAIN_ACCESS` - Alternatively, the `XCODE_KEYCHAIN` and `XCODE_KEYCHAIN_PASSWORD` in a single colon-separated string. Alternatively, on Travis we decrypt the actual certificate files and create a temporary keychain. To do this we need the password to the private key. That's stored in: - `APPLE_CODESIGN_KEY_PASSWORD` For signing builds on Windows only: - `CERTIFICATE_FILE` - The Windows certificate - `CERTIFICATE_PASSWORD` - The password for the private key on the cert To download Electron: - `NYLAS_GITHUB_OAUTH_TOKEN` - The OAuth token to use for GitHub API requests. See https://github.com/atom/grunt-download-electron To upload built artifacts to S3: - `AWS_ACCESS_KEY_ID` - `AWS_SECRET_ACCESS_KEY` To notify when builds are done: - `NYLAS_INTERNAL_HOOK_URL` - Nylas internal Slack token and url ================================================ FILE: packages/client-app/docs/README.md ================================================ These are now available at [https://nylas.github.io/nylas-mail](https://nylas.github.io/nylas-mail) ================================================ FILE: packages/client-app/dot-nylas/README.md ================================================ # Default Config These are the default Nylas configs. This folder on setup is copied to `~/.nylas-mail` on unix machines. ================================================ FILE: packages/client-app/dot-nylas/config.json ================================================ { "*": { "env": "production", "core": { "themes": [ "ui-light" ], "disabledPackages": [ "message-view-on-github", "personal-level-indicators", "phishing-detection", "nylas-private-salesforce", "github-contact-card", "keybase", "thread-sharing", "composer-markdown", "composer-scheduler", "composer-mail-merge", "send-and-archive", "main-calendar", "open-tracking", "link-tracking", "send-later", "thread-snooze", "activity-list" ] } } } ================================================ FILE: packages/client-app/dot-nylas/keymap.json ================================================ ================================================ FILE: packages/client-app/dot-nylas/packages/README.md ================================================ All packages in this directory will be automatically loaded ================================================ FILE: packages/client-app/internal_packages/account-sidebar/README.md ================================================ # React version of thread list ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/account-commands.coffee ================================================ _ = require 'underscore' {Actions, MenuHelpers} = require 'nylas-exports' class AccountCommands @_focusAccounts: (accounts) -> Actions.focusDefaultMailboxPerspectiveForAccounts(accounts) NylasEnv.show() unless NylasEnv.isVisible() @_isSelected: (account, sidebarAccountIds) => if sidebarAccountIds.length > 1 return account instanceof Array else if sidebarAccountIds.length is 1 return account?.id is sidebarAccountIds[0] else return false @registerCommands: (accounts) -> @_commandsDisposable?.dispose() commands = {} allKey = "window:select-account-0" commands[allKey] = @_focusAccounts.bind(@, accounts) [1..8].forEach (index) => account = accounts[index - 1] return unless account key = "window:select-account-#{index}" commands[key] = @_focusAccounts.bind(@, [account]) @_commandsDisposable = NylasEnv.commands.add(document.body, commands) @registerMenuItems: (accounts, sidebarAccountIds) -> windowMenu = _.find NylasEnv.menu.template, ({label}) -> MenuHelpers.normalizeLabel(label) is 'Window' return unless windowMenu submenu = _.reject windowMenu.submenu, (item) -> item.account return unless submenu idx = _.findIndex submenu, ({type}) -> type is 'separator' return unless idx > 0 template = @menuTemplate(accounts, sidebarAccountIds) submenu.splice(idx + 1, 0, template...) windowMenu.submenu = submenu NylasEnv.menu.update() @menuItem: (account, idx, {isSelected, clickHandlers} = {}) => item = { label: account.label ? "All Accounts", command: "window:select-account-#{idx}", account: true } if isSelected item.type = 'checkbox' item.checked = true if clickHandlers accounts = if account instanceof Array then account else [account] item.click = @_focusAccounts.bind(@, accounts) item.accelerator = "CmdOrCtrl+#{idx + 1}" return item @menuTemplate: (accounts, sidebarAccountIds, {clickHandlers} = {}) => template = [] multiAccount = accounts.length > 1 if multiAccount isSelected = @_isSelected(accounts, sidebarAccountIds) template = [ @menuItem(accounts, 0, {isSelected, clickHandlers}) ] template = template.concat accounts.map((account, idx) => # If there's only one account, it should be mapped to command+1, not command+2 accIdx = if multiAccount then idx + 1 else idx isSelected = @_isSelected(account, sidebarAccountIds) return @menuItem(account, accIdx, {isSelected, clickHandlers}) ) return template @register: (accounts, sidebarAccountIds) -> @registerCommands(accounts) @registerMenuItems(accounts, sidebarAccountIds) module.exports = AccountCommands ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/components/account-sidebar.cjsx ================================================ _ = require 'underscore' React = require 'react' {Utils, AccountStore} = require 'nylas-exports' {OutlineView, ScrollRegion, Flexbox} = require 'nylas-component-kit' AccountSwitcher = require './account-switcher' SidebarStore = require '../sidebar-store' class AccountSidebar extends React.Component @displayName: 'AccountSidebar' @containerRequired: false @containerStyles: minWidth: 165 maxWidth: 250 constructor: (@props) -> @state = @_getStateFromStores() componentDidMount: => @unsubscribers = [] @unsubscribers.push SidebarStore.listen @_onStoreChange @unsubscribers.push AccountStore.listen @_onStoreChange shouldComponentUpdate: (nextProps, nextState) => not Utils.isEqualReact(nextProps, @props) or not Utils.isEqualReact(nextState, @state) componentWillUnmount: => unsubscribe() for unsubscribe in @unsubscribers _onStoreChange: => @setState @_getStateFromStores() _getStateFromStores: => accounts: AccountStore.accounts() sidebarAccountIds: SidebarStore.sidebarAccountIds() userSections: SidebarStore.userSections() standardSection: SidebarStore.standardSection() _renderUserSections: (sections) => sections.map (section) => render: => {accounts, sidebarAccountIds, userSections, standardSection} = @state
{@_renderUserSections(userSections)}
module.exports = AccountSidebar ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/components/account-switcher.cjsx ================================================ React = require 'react' {Actions} = require 'nylas-exports' {RetinaImg} = require 'nylas-component-kit' AccountCommands = require '../account-commands' class AccountSwitcher extends React.Component @displayName: 'AccountSwitcher' @propTypes: accounts: React.PropTypes.array.isRequired sidebarAccountIds: React.PropTypes.array.isRequired _makeMenuTemplate: => template = AccountCommands.menuTemplate( @props.accounts, @props.sidebarAccountIds, clickHandlers: true ) template = template.concat [ {type: 'separator'} {label: 'Add Account...', click: @_onAddAccount} {label: 'Manage Accounts...', click: @_onManageAccounts} ] return template # Handlers _onAddAccount: => ipc = require('electron').ipcRenderer ipc.send('command', 'application:add-account', {source: 'Sidebar'}) _onManageAccounts: => Actions.switchPreferencesTab('Accounts') Actions.openPreferences() _onShowMenu: => remote = require('electron').remote Menu = remote.Menu menu = Menu.buildFromTemplate(@_makeMenuTemplate()) menu.popup() render: =>
module.exports = AccountSwitcher ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/main.coffee ================================================ React = require "react" AccountSidebar = require "./components/account-sidebar" {ComponentRegistry, WorkspaceStore} = require "nylas-exports" module.exports = item: null # The DOM item the main React component renders into activate: (@state) -> ComponentRegistry.register AccountSidebar, location: WorkspaceStore.Location.RootSidebar deactivate: (@state) -> ComponentRegistry.unregister(AccountSidebar) ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/sidebar-actions.coffee ================================================ Reflux = require 'reflux' Actions = [ 'focusAccounts', 'setKeyCollapsed', ] for idx in Actions Actions[idx] = Reflux.createAction(Actions[idx]) Actions[idx].sync = true module.exports = Actions ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/sidebar-item.coffee ================================================ _ = require 'underscore' _str = require 'underscore.string' {WorkspaceStore, MailboxPerspective, FocusedPerspectiveStore, SyncbackCategoryTask, DestroyCategoryTask, CategoryStore, Actions, Utils, RegExpUtils} = require 'nylas-exports' {OutlineViewItem} = require 'nylas-component-kit' SidebarActions = require './sidebar-actions' idForCategories = (categories) -> _.pluck(categories, 'id').join('-') countForItem = (perspective) -> unreadCountEnabled = NylasEnv.config.get('core.workspace.showUnreadForAllCategories') if perspective.isInbox() or unreadCountEnabled return perspective.unreadCount() return 0 isItemSelected = (perspective) -> (WorkspaceStore.rootSheet() in [WorkspaceStore.Sheet.Threads, WorkspaceStore.Sheet.Drafts] and FocusedPerspectiveStore.current().isEqual(perspective)) isItemCollapsed = (id) -> if NylasEnv.savedState.sidebarKeysCollapsed[id] isnt undefined NylasEnv.savedState.sidebarKeysCollapsed[id] else true toggleItemCollapsed = (item) -> return unless item.children.length > 0 SidebarActions.setKeyCollapsed(item.id, not isItemCollapsed(item.id)) onDeleteItem = (item) -> # TODO Delete multiple categories at once return if item.deleted is true category = item.perspective.category() return unless category Actions.queueTask(new DestroyCategoryTask({category})) onEditItem = (item, value) -> return unless value return if item.deleted is true category = item.perspective.category() return unless category re = RegExpUtils.subcategorySplitRegex() match = re.exec(category.displayName) lastMatch = match while match lastMatch = match match = re.exec(category.displayName) if lastMatch newDisplayName = category.displayName.slice(0, lastMatch.index + 1) + value else newDisplayName = value if newDisplayName is category.displayName return Actions.queueTask(new SyncbackCategoryTask({category, displayName: newDisplayName})) class SidebarItem @forPerspective: (id, perspective, opts = {}) -> counterStyle = OutlineViewItem.CounterStyles.Alt if perspective.isInbox() return _.extend({ id: id name: perspective.name contextMenuLabel: perspective.name count: countForItem(perspective) iconName: perspective.iconName children: [] perspective: perspective selected: isItemSelected(perspective) collapsed: isItemCollapsed(id) ? true counterStyle: counterStyle onDelete: if opts.deletable then onDeleteItem else undefined onEdited: if opts.editable then onEditItem else undefined onCollapseToggled: toggleItemCollapsed onDrop: (item, event) -> jsonString = event.dataTransfer.getData('nylas-threads-data') jsonData = null try jsonData = JSON.parse(jsonString) catch err console.error("JSON parse error: #{err}") return unless jsonData Actions.moveThreadsToPerspective({ targetPerspective: item.perspective, threadIds: jsonData.threadIds, accountIds: jsonData.accountIds, }) shouldAcceptDrop: (item, event) -> target = item.perspective current = FocusedPerspectiveStore.current() return false unless event.dataTransfer.types.includes('nylas-threads-data') return false if target.isEqual(current) # We can't inspect the drag payload until drop, so we use a dataTransfer # type to encode the account IDs of threads currently being dragged. accountsType = event.dataTransfer.types.find((t) => t.startsWith('nylas-accounts=')) accountIds = (accountsType || "").replace('nylas-accounts=', '').split(',') return target.canReceiveThreadsFromAccountIds(accountIds) onSelect: (item) -> Actions.focusMailboxPerspective(item.perspective) }, opts) @forCategories: (categories = [], opts = {}) -> id = idForCategories(categories) contextMenuLabel = _str.capitalize(categories[0]?.displayType()) perspective = MailboxPerspective.forCategories(categories) opts.deletable ?= true opts.editable ?= true opts.contextMenuLabel = contextMenuLabel @forPerspective(id, perspective, opts) @forSnoozed: (accountIds, opts = {}) -> # TODO This constant should be available elsewhere constants = require('../../thread-snooze/lib/snooze-constants') displayName = constants.SNOOZE_CATEGORY_NAME id = displayName id += "-#{opts.name}" if opts.name opts.name = "Snoozed" unless opts.name opts.iconName= 'snooze.png' categories = accountIds.map (accId) => _.findWhere CategoryStore.categories(accId), {displayName} categories = _.compact(categories) perspective = MailboxPerspective.forCategories(categories) perspective.name = id unless perspective.name @forPerspective(id, perspective, opts) @forStarred: (accountIds, opts = {}) -> perspective = MailboxPerspective.forStarred(accountIds) id = 'Starred' id += "-#{opts.name}" if opts.name @forPerspective(id, perspective, opts) @forUnread: (accountIds, opts = {}) -> categories = accountIds.map (accId) => CategoryStore.getStandardCategory(accId, 'inbox') # NOTE: It's possible for an account to not yet have an `inbox` # category. Since the `SidebarStore` triggers on `AccountStore` # changes, it'll trigger the exact moment an account is added to the # config. However, the API has not yet come back with the list of # `categories` for that account. categories = _.compact(categories) perspective = MailboxPerspective.forUnread(categories) id = 'Unread' id += "-#{opts.name}" if opts.name @forPerspective(id, perspective, opts) @forDrafts: (accountIds, opts = {}) -> perspective = MailboxPerspective.forDrafts(accountIds) id = "Drafts-#{opts.name}" @forPerspective(id, perspective, opts) module.exports = SidebarItem ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/sidebar-section.coffee ================================================ _ = require 'underscore' {Actions, SyncbackCategoryTask, DestroyCategoryTask, CategoryStore, Category, ExtensionRegistry, RegExpUtils} = require 'nylas-exports' SidebarItem = require './sidebar-item' SidebarActions = require './sidebar-actions' isSectionCollapsed = (title) -> if NylasEnv.savedState.sidebarKeysCollapsed[title] isnt undefined NylasEnv.savedState.sidebarKeysCollapsed[title] else false toggleSectionCollapsed = (section) -> return unless section SidebarActions.setKeyCollapsed(section.title, not isSectionCollapsed(section.title)) class SidebarSection @empty: (title) -> return { title, items: [] } @standardSectionForAccount: (account) -> if not account throw new Error("standardSectionForAccount: You must pass an account.") cats = CategoryStore.standardCategories(account) return @empty(account.label) if cats.length is 0 items = _ .reject(cats, (cat) -> cat.name is 'drafts') .map (cat) => SidebarItem.forCategories([cat], editable: false, deletable: false) unreadItem = SidebarItem.forUnread([account.id]) starredItem = SidebarItem.forStarred([account.id]) draftsItem = SidebarItem.forDrafts([account.id]) snoozedItem = SidebarItem.forSnoozed([account.id]) extensionItems = ExtensionRegistry.AccountSidebar.extensions() .filter((ext) => ext.sidebarItem?) .map((ext) => ext.sidebarItem([account.id])) .map(({id, name, iconName, perspective}) => SidebarItem.forPerspective(id, perspective, {name, iconName}) ) # Order correctly: Inbox, Unread, Starred, rest... , Drafts items.splice(1, 0, unreadItem, starredItem, snoozedItem, extensionItems...) items.push(draftsItem) return { title: account.label items: items } @standardSectionForAccounts: (accounts) -> return @empty('All Accounts') if not accounts or accounts.length is 0 return @empty('All Accounts') if CategoryStore.categories().length is 0 return @standardSectionForAccount(accounts[0]) if accounts.length is 1 standardNames = [ 'inbox', 'important' 'sent', ['archive', 'all'], 'spam' 'trash' ] items = [] for names in standardNames names = if Array.isArray(names) then names else [names] categories = CategoryStore.getStandardCategories(accounts, names...) continue if categories.length is 0 children = [] accounts.forEach (acc) -> cat = _.first(_.compact( names.map((name) -> CategoryStore.getStandardCategory(acc, name)) )) return unless cat children.push(SidebarItem.forCategories([cat], name: acc.label, editable: false, deletable: false)) items.push SidebarItem.forCategories(categories, {children, editable: false, deletable: false}) accountIds = _.pluck(accounts, 'id') starredItem = SidebarItem.forStarred(accountIds, children: accounts.map (acc) -> SidebarItem.forStarred([acc.id], name: acc.label) ) unreadItem = SidebarItem.forUnread(accountIds, children: accounts.map (acc) -> SidebarItem.forUnread([acc.id], name: acc.label) ) draftsItem = SidebarItem.forDrafts(accountIds, children: accounts.map (acc) -> SidebarItem.forDrafts([acc.id], name: acc.label) ) snoozedItem = SidebarItem.forSnoozed(accountIds, children: accounts.map (acc) -> SidebarItem.forSnoozed([acc.id], name: acc.label) ) extensionItems = ExtensionRegistry.AccountSidebar.extensions() .filter((ext) => ext.sidebarItem?) .map((ext) => {id, name, iconName, perspective} = ext.sidebarItem(accountIds) return SidebarItem.forPerspective(id, perspective, { name, iconName, children: accounts.map((acc) => subItem = ext.sidebarItem([acc.id]) return SidebarItem.forPerspective( subItem.id + "-#{acc.id}", subItem.perspective, {name: acc.label, iconName: subItem.iconName} ) ) }) ) # Order correctly: Inbox, Unread, Starred, rest... , Drafts items.splice(1, 0, unreadItem, starredItem, snoozedItem, extensionItems...) items.push(draftsItem) return { title: 'All Accounts' items: items } @forUserCategories: (account, {title, collapsible} = {}) -> return unless account # Compute hierarchy for user categories using known "path" separators # NOTE: This code uses the fact that userCategoryItems is a sorted set, eg: # # Inbox # Inbox.FolderA # Inbox.FolderA.FolderB # Inbox.FolderB # items = [] seenItems = {} for category in CategoryStore.userCategories(account) # https://regex101.com/r/jK8cC2/1 re = RegExpUtils.subcategorySplitRegex() itemKey = category.displayName.replace(re, '/') parent = null parentComponents = itemKey.split('/') for i in [parentComponents.length..1] by -1 parentKey = parentComponents[0...i].join('/') parent = seenItems[parentKey] break if parent if parent itemDisplayName = category.displayName.substr(parentKey.length+1) item = SidebarItem.forCategories([category], name: itemDisplayName) parent.children.push(item) else item = SidebarItem.forCategories([category]) items.push(item) seenItems[itemKey] = item title ?= account.categoryLabel() collapsed = isSectionCollapsed(title) if collapsible onCollapseToggled = toggleSectionCollapsed return { title: title iconName: account.categoryIcon() items: items collapsed: collapsed onCollapseToggled: onCollapseToggled onItemCreated: (displayName) -> return unless displayName category = new Category displayName: displayName accountId: account.id Actions.queueTask(new SyncbackCategoryTask({category})) } module.exports = SidebarSection ================================================ FILE: packages/client-app/internal_packages/account-sidebar/lib/sidebar-store.coffee ================================================ _ = require 'underscore' NylasStore = require 'nylas-store' {Actions, AccountStore, ThreadCountsStore, WorkspaceStore, OutboxStore, FocusedPerspectiveStore, CategoryStore} = require 'nylas-exports' SidebarSection = require './sidebar-section' SidebarActions = require './sidebar-actions' AccountCommands = require './account-commands' Sections = { "Standard", "User" } class SidebarStore extends NylasStore constructor: -> NylasEnv.savedState.sidebarKeysCollapsed ?= {} @_sections = {} @_sections[Sections.Standard] = {} @_sections[Sections.User] = [] @_registerCommands() @_registerMenuItems() @_registerListeners() @_updateSections() accounts: -> AccountStore.accounts() sidebarAccountIds: -> FocusedPerspectiveStore.sidebarAccountIds() standardSection: -> @_sections[Sections.Standard] userSections: -> @_sections[Sections.User] _registerListeners: -> @listenTo Actions.setCollapsedSidebarItem, @_onSetCollapsedByName @listenTo SidebarActions.setKeyCollapsed, @_onSetCollapsedByKey @listenTo AccountStore, @_onAccountsChanged @listenTo FocusedPerspectiveStore, @_onFocusedPerspectiveChanged @listenTo WorkspaceStore, @_updateSections @listenTo OutboxStore, @_updateSections @listenTo ThreadCountsStore, @_updateSections @listenTo CategoryStore, @_updateSections @configSubscription = NylasEnv.config.onDidChange( 'core.workspace.showUnreadForAllCategories', @_updateSections ) return _onSetCollapsedByKey: (itemKey, collapsed) => currentValue = NylasEnv.savedState.sidebarKeysCollapsed[itemKey] if currentValue isnt collapsed NylasEnv.savedState.sidebarKeysCollapsed[itemKey] = collapsed @_updateSections() _onSetCollapsedByName: (itemName, collapsed) => item = _.findWhere(@standardSection().items, {name: itemName}) if not item for section in @userSections() item = _.findWhere(section.items, {name: itemName}) break if item return unless item @_onSetCollapsedByKey(item.id, collapsed) _registerCommands: (accounts = AccountStore.accounts()) => AccountCommands.registerCommands(accounts) _registerMenuItems: (accounts = AccountStore.accounts()) => AccountCommands.registerMenuItems(accounts, FocusedPerspectiveStore.sidebarAccountIds()) # TODO Refactor this # Listen to changes on the account store only for when the account label # or order changes. When accounts or added or removed, those changes will # come in through the FocusedPerspectiveStore _onAccountsChanged: => @_updateSections() # TODO Refactor this # The FocusedPerspectiveStore tells this store the accounts that should be # displayed in the sidebar (i.e. unified inbox vs single account) and will # trigger whenever an account is added or removed, as well as when a # perspective is focused. # However, when udpating the SidebarSections, we also depend on the actual # accounts in the AccountStore. The problem is that the FocusedPerspectiveStore # triggers before the AccountStore is actually updated, so we need to wait for # the AccountStore to get updated (via `defer`) before updateing our sidebar # sections _onFocusedPerspectiveChanged: => _.defer => @_registerCommands() @_registerMenuItems() @_updateSections() _updateSections: => accounts = FocusedPerspectiveStore.sidebarAccountIds() .map((id) => AccountStore.accountForId(id)) .filter((a) => !!a) return if accounts.length is 0 multiAccount = accounts.length > 1 @_sections[Sections.Standard] = SidebarSection.standardSectionForAccounts(accounts) @_sections[Sections.User] = accounts.map (acc) -> opts = {} if multiAccount opts.title = acc.label opts.collapsible = true SidebarSection.forUserCategories(acc, opts) @trigger() module.exports = new SidebarStore() ================================================ FILE: packages/client-app/internal_packages/account-sidebar/package.json ================================================ { "name": "account-sidebar", "version": "0.1.0", "main": "./lib/main", "description": "Sidebar view that shows your account and important tags", "license": "GPL-3.0", "private": true, "engines": { "nylas": "*" } } ================================================ FILE: packages/client-app/internal_packages/account-sidebar/spec/sidebar-item-spec.es6 ================================================ import {Category, Actions} from "nylas-exports" import SidebarItem from "../lib/sidebar-item" describe("sidebar-item", function sidebarItemSpec() { it("preserves nested labels on rename", () => { spyOn(Actions, "queueTask") const categories = [new Category({displayName: 'a.b/c', accountId: window.TEST_ACCOUNT_ID})] NylasEnv.savedState.sidebarKeysCollapsed = {} const item = SidebarItem.forCategories(categories) item.onEdited(item, 'd') const task = Actions.queueTask.calls[0].args[0] expect(task.displayName).toBe("a.b/d") }) it("preserves labels on rename", () => { spyOn(Actions, "queueTask") const categories = [new Category({displayName: 'a', accountId: window.TEST_ACCOUNT_ID})] NylasEnv.savedState.sidebarKeysCollapsed = {} const item = SidebarItem.forCategories(categories) item.onEdited(item, 'b') const task = Actions.queueTask.calls[0].args[0] expect(task.displayName).toBe("b") }) }) ================================================ FILE: packages/client-app/internal_packages/account-sidebar/stylesheets/account-sidebar.less ================================================ @import "ui-variables"; @import "ui-mixins"; .account-sidebar { flex: 1; height: 100%; background-color: @source-list-bg; .item.deleted { opacity: 0.5; } .nylas-outline-view:first-child { .heading span { margin-right: 30px; } } } .account-switcher { position: absolute; top: 7px; right: 17px; z-index: 3; img { transform: rotateX(180deg); } } ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-data-source.es6 ================================================ import {Rx, Message, DatabaseStore} from 'nylas-exports'; export default class ActivityDataSource { buildObservable({openTrackingId, linkTrackingId, messageLimit}) { const query = DatabaseStore .findAll(Message) .order(Message.attributes.date.descending()) .where(Message.attributes.pluginMetadata.contains(openTrackingId, linkTrackingId)) .limit(messageLimit); this.observable = Rx.Observable.fromQuery(query); return this.observable; } subscribe(callback) { return this.observable.subscribe(callback); } } ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list-actions.es6 ================================================ import Reflux from 'reflux'; const ActivityListActions = Reflux.createActions([ "resetSeen", ]); for (const key of Object.keys(ActivityListActions)) { ActivityListActions[key].sync = true; } export default ActivityListActions; ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list-button.jsx ================================================ import React from 'react'; import {Actions, ReactDOM} from 'nylas-exports'; import {RetinaImg} from 'nylas-component-kit'; import ActivityList from './activity-list'; import ActivityListStore from './activity-list-store'; class ActivityListButton extends React.Component { static displayName = 'ActivityListButton'; constructor() { super(); this.state = this._getStateFromStores(); } componentDidMount() { this._unsub = ActivityListStore.listen(this._onDataChanged); } componentWillUnmount() { this._unsub(); } onClick = () => { const buttonRect = ReactDOM.findDOMNode(this).getBoundingClientRect(); Actions.openPopover( , {originRect: buttonRect, direction: 'down'} ); } _onDataChanged = () => { this.setState(this._getStateFromStores()); } _getStateFromStores() { return { unreadCount: ActivityListStore.unreadCount(), } } render() { let unreadCountClass = "unread-count"; let iconClass = "activity-toolbar-icon"; if (this.state.unreadCount) { unreadCountClass += " active"; iconClass += " unread"; } return (
{this.state.unreadCount}
); } } export default ActivityListButton; ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list-empty-state.jsx ================================================ import React from 'react'; import {RetinaImg} from 'nylas-component-kit'; const ActivityListEmptyState = function ActivityListEmptyState() { return (
Enable read receipts or link tracking to see notifications here.
); } export default ActivityListEmptyState; ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list-item-container.jsx ================================================ import React from 'react'; import {DisclosureTriangle, Flexbox, RetinaImg} from 'nylas-component-kit'; import {DateUtils} from 'nylas-exports'; import ActivityListStore from './activity-list-store'; import {pluginFor} from './plugin-helpers'; class ActivityListItemContainer extends React.Component { static displayName = 'ActivityListItemContainer'; static propTypes = { group: React.PropTypes.array, }; constructor(props) { super(props); this.state = { collapsed: true, }; } _onClick(threadId) { ActivityListStore.focusThread(threadId); } _onCollapseToggled = (event) => { event.stopPropagation(); this.setState({collapsed: !this.state.collapsed}); } _getText() { const text = { recipient: "Someone", title: "(No Subject)", date: new Date(0), }; const lastAction = this.props.group[0]; if (this.props.group.length === 1 && lastAction.recipient) { text.recipient = lastAction.recipient.displayName(); } else if (this.props.group.length > 1 && lastAction.recipient) { const people = []; for (const action of this.props.group) { if (!people.includes(action.recipient)) { people.push(action.recipient); } } if (people.length === 1) text.recipient = people[0].displayName(); else if (people.length === 2) text.recipient = `${people[0].displayName()} and 1 other`; else text.recipient = `${people[0].displayName()} and ${people.length - 1} others`; } if (lastAction.title) text.title = lastAction.title; text.date.setUTCSeconds(lastAction.timestamp); return text; } renderActivityContainer() { if (this.props.group.length === 1) return null; const actions = []; for (const action of this.props.group) { const date = new Date(0); date.setUTCSeconds(action.timestamp); actions.push(
{action.recipient ? action.recipient.displayName() : "Someone"}
{DateUtils.shortTimeString(date)}
); } return (
{actions}
); } render() { const lastAction = this.props.group[0]; let className = "activity-list-item"; if (!ActivityListStore.hasBeenViewed(lastAction)) className += " unread"; const text = this._getText(); let disclosureTriangle = (
); if (this.props.group.length > 1) { disclosureTriangle = ( ); } return (
{ this._onClick(lastAction.threadId) }}>
{disclosureTriangle}
{text.recipient} {pluginFor(lastAction.pluginId).predicate}:
{DateUtils.shortTimeString(text.date)}
{text.title}
{this.renderActivityContainer()}
); } } export default ActivityListItemContainer; ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list-store.jsx ================================================ import NylasStore from 'nylas-store'; import { Actions, Thread, DatabaseStore, NativeNotifications, FocusedPerspectiveStore, } from 'nylas-exports'; import ActivityListActions from './activity-list-actions'; import ActivityDataSource from './activity-data-source'; import {pluginFor} from './plugin-helpers'; class ActivityListStore extends NylasStore { activate() { this._getActivity(); this.listenTo(ActivityListActions.resetSeen, this._onResetSeen); this.listenTo(FocusedPerspectiveStore, this._updateActivity); } actions() { return this._actions; } unreadCount() { if (this._unreadCount < 1000) { return this._unreadCount; } else if (!this._unreadCount) { return null; } return "999+"; } hasBeenViewed(action) { if (!NylasEnv.savedState.activityListViewed) return false; return action.timestamp < NylasEnv.savedState.activityListViewed; } focusThread(threadId) { NylasEnv.displayWindow() Actions.closePopover() DatabaseStore.find(Thread, threadId).then((thread) => { if (!thread) { NylasEnv.reportError(new Error(`ActivityListStore::focusThread: Can't find thread`, {threadId})) NylasEnv.showErrorDialog(`Can't find the selected thread in your mailbox`) return; } Actions.ensureCategoryIsFocused('sent', thread.accountId); Actions.setFocus({collection: 'thread', item: thread}); }); } getRecipient(recipientEmail, recipients) { if (recipientEmail) { for (const recipient of recipients) { if (recipientEmail === recipient.email) { return recipient; } } } else if (recipients.length === 1) { return recipients[0]; } return null; } _dataSource() { return new ActivityDataSource(); } _onResetSeen() { NylasEnv.savedState.activityListViewed = Date.now() / 1000; this._unreadCount = 0; this.trigger(); } _getActivity() { const dataSource = this._dataSource(); this._subscription = dataSource.buildObservable({ openTrackingId: NylasEnv.packages.pluginIdFor('open-tracking'), linkTrackingId: NylasEnv.packages.pluginIdFor('link-tracking'), messageLimit: 500, }).subscribe((messages) => { this._messages = messages; this._updateActivity(); }); } _updateActivity() { this._actions = this._messages ? this._getActions(this._messages) : []; this.trigger(); } _getActions(messages) { let actions = []; this._notifications = []; this._unreadCount = 0; const sidebarAccountIds = FocusedPerspectiveStore.sidebarAccountIds(); for (const message of messages) { if (sidebarAccountIds.length > 1 || message.accountId === sidebarAccountIds[0]) { const openTrackingId = NylasEnv.packages.pluginIdFor('open-tracking') const linkTrackingId = NylasEnv.packages.pluginIdFor('link-tracking') if (message.metadataForPluginId(openTrackingId) || message.metadataForPluginId(linkTrackingId)) { actions = actions.concat(this._openActionsForMessage(message)); actions = actions.concat(this._linkActionsForMessage(message)); } } } if (!this._lastNotified) this._lastNotified = {}; for (const notification of this._notifications) { const lastNotified = this._lastNotified[notification.threadId]; const {notificationInterval} = pluginFor(notification.pluginId); if (!lastNotified || lastNotified < Date.now() - notificationInterval) { NativeNotifications.displayNotification(notification.data); this._lastNotified[notification.threadId] = Date.now(); } } const d = new Date(); this._lastChecked = d.getTime() / 1000; actions = actions.sort((a, b) => b.timestamp - a.timestamp); // For performance reasons, only display the last 100 actions if (actions.length > 100) { actions.length = 100; } return actions; } _openActionsForMessage(message) { const openTrackingId = NylasEnv.packages.pluginIdFor('open-tracking') const openMetadata = message.metadataForPluginId(openTrackingId); const recipients = message.to.concat(message.cc, message.bcc); const actions = []; if (openMetadata) { if (openMetadata.open_count > 0) { for (const open of openMetadata.open_data) { const recipient = this.getRecipient(open.recipient, recipients); if (open.timestamp > this._lastChecked) { this._notifications.push({ pluginId: openTrackingId, threadId: message.threadId, data: { title: "New open", subtitle: `${recipient ? recipient.displayName() : "Someone"} just opened ${message.subject}`, canReply: false, tag: "message-open", onActivate: () => { this.focusThread(message.threadId); }, }, }); } if (!this.hasBeenViewed(open)) this._unreadCount += 1; actions.push({ messageId: message.id, threadId: message.threadId, title: message.subject, recipient: recipient, pluginId: openTrackingId, timestamp: open.timestamp, }); } } } return actions; } _linkActionsForMessage(message) { const linkTrackingId = NylasEnv.packages.pluginIdFor('link-tracking') const linkMetadata = message.metadataForPluginId(linkTrackingId) const recipients = message.to.concat(message.cc, message.bcc); const actions = []; if (linkMetadata && linkMetadata.links) { for (const link of linkMetadata.links) { for (const click of link.click_data) { const recipient = this.getRecipient(click.recipient, recipients); if (click.timestamp > this._lastChecked) { this._notifications.push({ pluginId: linkTrackingId, threadId: message.threadId, data: { title: "New click", subtitle: `${recipient ? recipient.displayName() : "Someone"} just clicked ${link.url}.`, canReply: false, tag: "link-open", onActivate: () => { this.focusThread(message.threadId); }, }, }); } if (!this.hasBeenViewed(click)) this._unreadCount += 1; actions.push({ messageId: message.id, threadId: message.threadId, title: link.url, recipient: recipient, pluginId: linkTrackingId, timestamp: click.timestamp, }); } } } return actions; } } export default new ActivityListStore(); ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/activity-list.jsx ================================================ import React from 'react'; import classnames from 'classnames'; import {Flexbox, ScrollRegion} from 'nylas-component-kit'; import ActivityListStore from './activity-list-store'; import ActivityListActions from './activity-list-actions'; import ActivityListItemContainer from './activity-list-item-container'; import ActivityListEmptyState from './activity-list-empty-state'; class ActivityList extends React.Component { static displayName = 'ActivityList'; constructor() { super(); this.state = this._getStateFromStores(); } componentDidMount() { this._unsub = ActivityListStore.listen(this._onDataChanged); } componentWillUnmount() { ActivityListActions.resetSeen(); this._unsub(); } _onDataChanged = () => { this.setState(this._getStateFromStores()); } _getStateFromStores() { const actions = ActivityListStore.actions(); return { actions: actions, empty: actions instanceof Array && actions.length === 0, collapsedToggles: this.state ? this.state.collapsedToggles : {}, } } _groupActions(actions) { const groupedActions = []; for (const action of actions) { if (groupedActions.length > 0) { const currentGroup = groupedActions[groupedActions.length - 1]; if (action.messageId === currentGroup[0].messageId && action.pluginId === currentGroup[0].pluginId) { groupedActions[groupedActions.length - 1].push(action); } else { groupedActions.push([action]); } } else { groupedActions.push([action]); } } return groupedActions; } renderActions() { if (this.state.empty) { return ( ) } const groupedActions = this._groupActions(this.state.actions); return groupedActions.map((group) => { return ( ); }); } render() { if (!this.state.actions) return null; const classes = classnames({ "activity-list-container": true, "empty": this.state.empty, }) return ( {this.renderActions()} ); } } export default ActivityList; ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/main.es6 ================================================ import {ComponentRegistry, WorkspaceStore} from 'nylas-exports'; import {HasTutorialTip} from 'nylas-component-kit'; import ActivityListButton from './activity-list-button'; import ActivityListStore from './activity-list-store'; const ActivityListButtonWithTutorialTip = HasTutorialTip(ActivityListButton, { title: "Open and link tracking", instructions: "If you've enabled link tracking or read receipts, those events will appear here!", }); export function activate() { ComponentRegistry.register(ActivityListButtonWithTutorialTip, { location: WorkspaceStore.Location.RootSidebar.Toolbar, }); ActivityListStore.activate(); } export function deactivate() { ComponentRegistry.unregister(ActivityListButtonWithTutorialTip); } ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/plugin-helpers.es6 ================================================ export function pluginFor(id) { const openTrackingId = NylasEnv.packages.pluginIdFor('open-tracking') const linkTrackingId = NylasEnv.packages.pluginIdFor('link-tracking') if (id === openTrackingId) { return { name: "open", predicate: "opened", iconName: "icon-activity-mailopen.png", notificationInterval: 600000, // 10 minutes in ms } } if (id === linkTrackingId) { return { name: "link", predicate: "clicked", iconName: "icon-activity-linkopen.png", notificationInterval: 10000, // 10 seconds in ms } } return undefined } ================================================ FILE: packages/client-app/internal_packages/activity-list/lib/test-data-source.es6 ================================================ export default class TestDataSource { buildObservable() { return this; } manuallyTrigger = (messages = []) => { this.onNext(messages); } subscribe(onNext) { this.onNext = onNext; this.manuallyTrigger(); const dispose = () => { this._unsub(); } return {dispose}; } } ================================================ FILE: packages/client-app/internal_packages/activity-list/package.json ================================================ { "name": "activity-list", "main": "./lib/main", "version": "0.1.0", "repository": { "type": "git", "url": "" }, "engines": { "nylas": "*" }, "isOptional": true, "title":"Activity List", "icon":"./assets/icon.png", "description": "Get notifications for open and link tracking activity.", "supportedEnvs": ["development", "staging", "production"], "license": "GPL-3.0" } ================================================ FILE: packages/client-app/internal_packages/activity-list/spec/activity-list-spec.jsx ================================================ import React from 'react'; import ReactTestUtils from 'react-addons-test-utils'; import { Thread, Actions, Contact, Message, DatabaseStore, FocusedPerspectiveStore, } from 'nylas-exports'; import ActivityList from '../lib/activity-list'; import ActivityListStore from '../lib/activity-list-store'; import TestDataSource from '../lib/test-data-source'; const OPEN_TRACKING_ID = 'open-tracking-id' const LINK_TRACKING_ID = 'link-tracking-id' const messages = [ new Message({ accountId: "0000000000000000000000000", bcc: [], cc: [], snippet: "Testing.", subject: "Open me!", threadId: "0000000000000000000000000", to: [new Contact({ name: "Jackie Luo", email: "jackie@nylas.com", })], }), new Message({ accountId: "0000000000000000000000000", bcc: [new Contact({ name: "Ben Gotow", email: "ben@nylas.com", })], cc: [], snippet: "Hey! I am in town for the week...", subject: "Coffee?", threadId: "0000000000000000000000000", to: [new Contact({ name: "Jackie Luo", email: "jackie@nylas.com", })], }), new Message({ accountId: "0000000000000000000000000", bcc: [], cc: [new Contact({ name: "Evan Morikawa", email: "evan@nylas.com", })], snippet: "Here's the latest deals!", subject: "Newsletter", threadId: "0000000000000000000000000", to: [new Contact({ name: "Juan Tejada", email: "juan@nylas.com", })], }), ]; let pluginValue = { open_count: 1, open_data: [{ timestamp: 1461361759.351055, }], }; messages[0].applyPluginMetadata(OPEN_TRACKING_ID, pluginValue); pluginValue = { links: [{ click_count: 1, click_data: [{ timestamp: 1461349232.495837, }], }], tracked: true, }; messages[0].applyPluginMetadata(LINK_TRACKING_ID, pluginValue); pluginValue = { open_count: 1, open_data: [{ timestamp: 1461361763.283720, }], }; messages[1].applyPluginMetadata(OPEN_TRACKING_ID, pluginValue); pluginValue = { links: [], tracked: false, }; messages[1].applyPluginMetadata(LINK_TRACKING_ID, pluginValue); pluginValue = { open_count: 0, open_data: [], }; messages[2].applyPluginMetadata(OPEN_TRACKING_ID, pluginValue); pluginValue = { links: [{ click_count: 0, click_data: [], }], tracked: true, }; messages[2].applyPluginMetadata(LINK_TRACKING_ID, pluginValue); describe('ActivityList', function activityList() { beforeEach(() => { this.testSource = new TestDataSource(); spyOn(NylasEnv.packages, 'pluginIdFor').andCallFake((pluginName) => { if (pluginName === 'open-tracking') { return OPEN_TRACKING_ID } if (pluginName === 'link-tracking') { return LINK_TRACKING_ID } return null }) spyOn(ActivityListStore, "_dataSource").andReturn(this.testSource); spyOn(FocusedPerspectiveStore, "sidebarAccountIds").andReturn(["0000000000000000000000000"]); spyOn(DatabaseStore, "run").andCallFake((query) => { if (query._klass === Thread) { const thread = new Thread({ id: "0000000000000000000000000", accountId: TEST_ACCOUNT_ID, }); return Promise.resolve(thread); } return null; }); spyOn(ActivityListStore, "focusThread").andCallThrough(); spyOn(NylasEnv, "displayWindow"); spyOn(Actions, "closePopover"); spyOn(Actions, "setFocus"); spyOn(Actions, "ensureCategoryIsFocused"); ActivityListStore.activate(); this.component = ReactTestUtils.renderIntoDocument(); }); describe('when no actions are found', () => { it('should show empty state', () => { const items = ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item"); expect(items.length).toBe(0); }); }); describe('when actions are found', () => { it('should show activity list items', () => { this.testSource.manuallyTrigger(messages); waitsFor(() => { const items = ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item"); return items.length > 0; }); runs(() => { expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item").length).toBe(3); }); }); it('should show the correct items', () => { this.testSource.manuallyTrigger(messages); waitsFor(() => { const items = ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item"); return items.length > 0; }); runs(() => { expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item")[0].textContent).toBe("Someone opened:Apr 22 2016Coffee?"); expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item")[1].textContent).toBe("Jackie Luo opened:Apr 22 2016Open me!"); expect(ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item")[2].textContent).toBe("Jackie Luo clicked:Apr 22 2016(No Subject)"); }); }); xit('should focus the thread', () => { runs(() => { return this.testSource.manuallyTrigger(messages); }) waitsFor(() => { const items = ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item"); return items.length > 0; }); runs(() => { const item = ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, "activity-list-item")[0]; ReactTestUtils.Simulate.click(item); }); waitsFor(() => { return ActivityListStore.focusThread.calls.length > 0; }); runs(() => { expect(NylasEnv.displayWindow.calls.length).toBe(1); expect(Actions.closePopover.calls.length).toBe(1); expect(Actions.setFocus.calls.length).toBe(1); expect(Actions.ensureCategoryIsFocused.calls.length).toBe(1); }); }); }); }); ================================================ FILE: packages/client-app/internal_packages/activity-list/stylesheets/activity-list.less ================================================ @import "ui-variables"; .toolbar-activity { order: 100; position: relative; .unread-count { display: none; &.active { display: inline-block; background: @component-active-color; text-align: center; color: @white; border-radius: @border-radius-base; font-size: 8px; padding: 0 4px; position: absolute; right: -7px; top: 5px; line-height: 11px; } } .activity-toolbar-icon { margin-top: 20px; background: @gray; &.unread { background: @component-active-color; } } } .activity-list-container { width: 260px; overflow: hidden; font-size: @font-size-small; color: @text-color-subtle; .spacer { flex: 1 1 0; } height: 282px; &.empty { height: 182px; } .empty { text-align: center; padding: @padding-base-horizontal * 2; padding-top: @padding-base-vertical * 8; img.logo { background-color: @text-color-very-subtle; } .text { margin-top: @padding-base-vertical * 6; color: @text-color-very-subtle; } } .activity-list-item { padding: @padding-small-vertical @padding-small-horizontal; white-space: nowrap; border-bottom: 1px solid @border-color-primary; cursor: default; &.unread { color: @text-color; background: @background-primary; &:hover { background: darken(@background-primary, 2%); } .action-message { font-weight: 600; } } &:hover { background: darken(@background-secondary, 2%); } .disclosure-triangle { padding-top: 5px; padding-bottom: 0; } .activity-icon-container { flex-shrink: 0; } .activity-icon { vertical-align: text-bottom; } .action-message, .title { text-overflow: ellipsis; overflow: hidden; } .timestamp { color: @text-color-very-subtle; text-overflow: ellipsis; overflow: hidden; flex-shrink: 0; padding-left: 5px; } } .activity-list-toggle-item { height: 30px; white-space: nowrap; background: @background-secondary; cursor: default; overflow-y: hidden; transition-property: all; transition-duration: .5s; transition-timing-function: cubic-bezier(0, 1, 0.5, 1); &:last-child { border-bottom: 1px solid @border-color-primary; } .action-message { padding: @padding-small-vertical @padding-small-horizontal; text-overflow: ellipsis; overflow: hidden; } .timestamp { padding: @padding-small-vertical @padding-small-horizontal; color: @text-color-very-subtle; text-overflow: ellipsis; overflow: hidden; } } .activity-toggle-container { &.hidden { .activity-list-toggle-item { height: 0; &:last-child { border-bottom: none; } } } } } body.platform-win32, body.platform-linux { .toolbar-activity { margin-right: @padding-base-horizontal; } } ================================================ FILE: packages/client-app/internal_packages/attachments/lib/main.es6 ================================================ import {ComponentRegistry} from 'nylas-exports'; import MessageAttachments from './message-attachments' export function activate() { ComponentRegistry.register(MessageAttachments, {role: 'MessageAttachments'}) } export function deactivate() { ComponentRegistry.unregister(MessageAttachments); } ================================================ FILE: packages/client-app/internal_packages/attachments/lib/message-attachments.jsx ================================================ import React, {Component, PropTypes} from 'react' import {Actions, Utils, FileDownloadStore} from 'nylas-exports' import {AttachmentItem, ImageAttachmentItem} from 'nylas-component-kit' class MessageAttachments extends Component { static displayName = 'MessageAttachments' static containerRequired = false static propTypes = { files: PropTypes.array, downloads: PropTypes.object, messageClientId: PropTypes.string, filePreviewPaths: PropTypes.object, canRemoveAttachments: PropTypes.bool, } static defaultProps = { downloads: {}, filePreviewPaths: {}, } onOpenAttachment = (file) => { Actions.fetchAndOpenFile(file) } onRemoveAttachment = (file) => { const {messageClientId} = this.props Actions.removeFile({ file: file, messageClientId: messageClientId, }) } onDownloadAttachment = (file) => { Actions.fetchAndSaveFile(file) } onAbortDownload = (file) => { Actions.abortFetchFile(file) } renderAttachment(AttachmentRenderer, file) { const {canRemoveAttachments, downloads, filePreviewPaths} = this.props const download = downloads[file.id] const filePath = FileDownloadStore.pathForFile(file) const fileIconName = `file-${file.displayExtension()}.png` const displayName = file.displayName() const displaySize = file.displayFileSize() const contentType = file.contentType const displayFilePreview = NylasEnv.config.get('core.attachments.displayFilePreview') const filePreviewPath = displayFilePreview ? filePreviewPaths[file.id] : null; return ( this.onOpenAttachment(file)} onDownloadAttachment={() => this.onDownloadAttachment(file)} onAbortDownload={() => this.onAbortDownload(file)} onRemoveAttachment={canRemoveAttachments ? () => this.onRemoveAttachment(file) : null} /> ) } render() { const {files} = this.props; const nonImageFiles = files.filter((f) => !Utils.shouldDisplayAsImage(f)); const imageFiles = files.filter((f) => Utils.shouldDisplayAsImage(f)); return (
{nonImageFiles.map((file) => this.renderAttachment(AttachmentItem, file) )} {imageFiles.map((file) => this.renderAttachment(ImageAttachmentItem, file) )}
) } } export default MessageAttachments ================================================ FILE: packages/client-app/internal_packages/attachments/package.json ================================================ { "name": "attachments", "version": "0.1.0", "main": "./lib/main", "description": "View attachments on messages", "license": "GPL-3.0", "private": true, "engines": { "nylas": "*" }, "windowTypes": { "default": true, "composer": true, "composer-preload": true, "thread-popout": true } } ================================================ FILE: packages/client-app/internal_packages/category-mapper/lib/category-selection.jsx ================================================ import { Menu, RetinaImg, DropdownMenu, LabelColorizer, BoldedSearchResult, } from 'nylas-component-kit' import { Utils, React, } from 'nylas-exports' import {Categories} from 'nylas-observables' export default class CategorySelection extends React.Component { static propTypes = { account: React.PropTypes.object, currentCategory: React.PropTypes.string, } constructor(props) { super(props) this._categories = [] this.state = { categoryData: this._recalculateCategories({searchValue: ''}), searchValue: "", } } componentDidMount() { this._disposable = Categories.forAccount(this.props.account).sort().subscribe(this._onCategoriesChanged) } shouldComponentUpdate(nextProps, nextState) { return !(Utils.isEqualReact(nextState, this.state) && Utils.isEqualReact(nextProps, this.props)) } componentWillUnmount() { this._disposable.dispose() } _isInSearch = (searchValue, category) => { return Utils.wordSearchRegExp(searchValue).test(category.displayName) }; _isUserFacing = (category) => { const hiddenCategories = ['N1-Snoozed', 'EI'] return !hiddenCategories.includes(category.displayName) }; _itemForCategory = (category) => { if (!category.divider) { category.backgroundColor = LabelColorizer.backgroundColorDark(category) } return category }; _recalculateCategories = ({searchValue = this.state.searchValue} = {}) => { let categories = this._categories if (!this.props.account.usesLabels()) { const standardCategories = categories.filter((cat) => cat.isStandardCategory()) const userCategories = categories.filter((cat) => cat.isUserCategory()) categories = standardCategories .concat([{divider: true, id: "category-divider"}]) .concat(userCategories) } const categoryData = categories .filter(this._isUserFacing) .filter(c => this._isInSearch(searchValue, c)) .map(this._itemForCategory) return categoryData }; _onCategoriesChanged = (categories) => { this._categories = categories this.setState({categoryData: this._recalculateCategories()}) }; _onSearchValueChange = (event) => { const searchValue = event.target.value; this.setState({ searchValue, categoryData: this._recalculateCategories({searchValue}), }) }; _renderFolderIcon = (item) => { return ( ) }; _renderLabelIcon = (item) => { return ( ) } _renderItem = (item = {empty: true}) => { if (item.divider) { return } let icon; if (item.empty) { icon = (
) item.displayName = "(None)" } else { icon = this.props.account.usesLabels() ? this._renderLabelIcon(item) : this._renderFolderIcon(item); } return (
{icon}
) }; render() { const placeholder = this.props.account.usesLabels() ? 'Choose folder or label' : 'Choose folder' const headerComponents = [ , ] return (
item.id} itemContent={this._renderItem} defaultSelectedIndex={this.state.searchValue === "" ? -1 : 0} {...this.props} />
) } } ================================================ FILE: packages/client-app/internal_packages/category-mapper/lib/main.es6 ================================================ import {PreferencesUIStore} from 'nylas-exports'; import PreferencesCategoryMapper from './preferences-category-mapper' export function activate() { this.preferencesTab = new PreferencesUIStore.TabItem({ tabId: "Folders", displayName: "Folders", component: PreferencesCategoryMapper, }); PreferencesUIStore.registerPreferencesTab(this.preferencesTab); } export function deactivate() { PreferencesUIStore.unregisterPreferencesTab(this.preferencesTab.sectionId) } ================================================ FILE: packages/client-app/internal_packages/category-mapper/lib/preferences-category-mapper.jsx ================================================ import { AccountStore, Category, DatabaseStore, NylasAPI, NylasAPIRequest, React, } from 'nylas-exports' import CategorySelection from './category-selection' const ROLES = ['inbox', 'sent', 'drafts', 'spam', 'trash'] export default class PreferencesCategoryMapper extends React.Component { constructor() { super() this.state = {ready: false} this._mounted = false this._populateRoleAssignments() } componentDidMount() { this._mounted = true this._populateRoleAssignments() } componentWillUnmount() { this._mounted = false } async _populateRoleAssignments() { const roleAssignment = {} await Promise.all(ROLES.map(async (role) => { const existingAssignments = await DatabaseStore.findAll(Category).where([ Category.attributes.name.equal(role), ]) for (const category of existingAssignments) { const {accountId} = category; if (!roleAssignment[accountId]) { roleAssignment[accountId] = {} } roleAssignment[accountId][role] = category } })) if (this._mounted) { this.setState({ready: true, roleAssignment}) } } _onCategorySelection = async (account, role, category) => { const {roleAssignment} = this.state; const originalRole = category.name category.name = role await DatabaseStore.inTransaction(t => t.persistModel(category)) const originalCategory = roleAssignment[account.id][role] roleAssignment[account.id][role] = category this.setState({roleAssignment}) try { const request = new NylasAPIRequest({ api: NylasAPI, options: { path: `/${category.displayType()}s/${category.id}`, accountId: category.accountId, method: "PUT", body: {role}, }, }) await request.run() } catch (err) { err.message = `Could not set ${category.displayName} as ${role} ${category.displayType()}: ${err.message}` NylasEnv.reportError(err) NylasEnv.showErrorDialog(err.message, {detail: err.stack}) // Revert optimistic changes category.name = originalRole await DatabaseStore.inTransaction(t => t.persistModel(category)) roleAssignment[account.id][role] = originalCategory this.setState({roleAssignment}) } } _renderAccountSection = (account) => { const roleSections = ROLES.map(role => this._renderRoleSection(account, role)) return (
{account.label}
{roleSections}
) } _renderRoleSection = (account, role) => { return (
{role}:
this._onCategorySelection(account, role, category)} />
) } render() { if (!this.state.ready) { return } const accountSections = AccountStore.accounts().map(this._renderAccountSection) return (
{accountSections}
) } } ================================================ FILE: packages/client-app/internal_packages/category-mapper/package.json ================================================ { "name": "category-mapper", "version": "0.1.0", "main": "./lib/main", "description": "Allow users to manually map roles to categories", "license": "GPL-3.0", "private": true, "engines": { "nylas": "*" } } ================================================ FILE: packages/client-app/internal_packages/category-mapper/stylesheets/category-mapper.less ================================================ @import "ui-variables"; .category-mapper-container { width: 40%; min-width: 460px; margin: 0 auto; } .account-section-title { border-bottom: 1px solid @border-color-divider; margin: @padding-large-vertical * 1.5 0; } input.search { border: 1px solid darken(@background-secondary, 10%); border-radius: 3px; background-color: @background-primary; box-shadow: inset 0 1px 0 rgba(0,0,0,0.05), 0 1px 0 rgba(0,0,0,0.05); color: @text-color; padding-left: 0; background-repeat: no-repeat; background-image: url("../static/images/search/searchloupe@2x.png"); background-size: 15px 15px; background-position: 7px 4px; text-indent: 31px; } .role-section { display: flex; .col-left { color: @text-color-very-subtle; text-align: right; flex: 1; margin-right: 20px; } .col-right { text-align: left; flex: 1; } } .category-selection { .menu { background: @background-secondary; width: 250px; max-height: 400px; box-shadow: 0 0.5px 0 rgba(0, 0, 0, 0.15), 0 -0.5px 0 rgba(0, 0, 0, 0.15), 0.5px 0 0 rgba(0, 0, 0, 0.15), -0.5px 0 0 rgba(0, 0, 0, 0.15), 0 4px 7px rgba(0,0,0,0.15); .header-container { border-bottom: 0; } .item.divider { background-color: #e0e0e0; margin: 4px 0; height: 2px; padding: 0; } } .category-item { font-size: 14px; display: flex; img.content-mask { position: relative; top:3px; background-color: @text-color-subtle; } } .category-display-name { display: inline-block; margin-left: 10px; margin-right: 5px; word-break: break-word; flex: 1; } } ================================================ FILE: packages/client-app/internal_packages/category-picker/lib/category-picker-popover.jsx ================================================ /* eslint jsx-a11y/tabindex-no-positive: 0 */ import _ from 'underscore' import React, {Component, PropTypes} from 'react' import { Menu, RetinaImg, LabelColorizer, BoldedSearchResult, } from 'nylas-component-kit' import { Utils, Actions, TaskQueueStatusStore, DatabaseStore, TaskFactory, Category, SyncbackCategoryTask, CategoryStore, FocusedPerspectiveStore, } from 'nylas-exports' import {Categories} from 'nylas-observables' export default class CategoryPickerPopover extends Component { static propTypes = { threads: PropTypes.array.isRequired, account: PropTypes.object.isRequired, }; constructor(props) { super(props) this._categories = [] this._standardCategories = [] this._userCategories = [] this.state = this._recalculateState(this.props, {searchValue: ''}) } componentDidMount() { this._registerObservables() } componentWillReceiveProps(nextProps) { this._registerObservables(nextProps) this.setState(this._recalculateState(nextProps)) } componentWillUnmount() { this._unregisterObservables() } _registerObservables = (props = this.props) => { this._unregisterObservables() this.disposables = [ Categories.forAccount(props.account).sort().subscribe(this._onCategoriesChanged), ] }; _unregisterObservables = () => { if (this.disposables) { this.disposables.forEach(disp => disp.dispose()) } }; _isInSearch = (searchValue, category) => { return Utils.wordSearchRegExp(searchValue).test(category.displayName) }; _isUserFacing = (allInInbox, category) => { const currentCategories = FocusedPerspectiveStore.current().categories() || [] const currentCategoryIds = _.pluck(currentCategories, 'id') const {account} = this.props let hiddenCategories = [] if (account) { if (account.usesLabels()) { hiddenCategories = Category.StandardCategoryNames.concat(["starred", "N1-Snoozed"]) if (allInInbox) { hiddenCategories.push("inbox") } if (category.divider) { return false } } else if (account.usesFolders()) { hiddenCategories = ["drafts", "sent", "N1-Snoozed"] } } return ( (!hiddenCategories.includes(category.name)) && (!hiddenCategories.includes(category.displayName)) && (!currentCategoryIds.includes(category.id)) ) }; _itemForCategory = ({usageCount, numThreads}, category) => { if (category.divider) { return category } const item = category.toJSON() item.category = category item.backgroundColor = LabelColorizer.backgroundColorDark(category) item.usage = usageCount[category.id] || 0 item.numThreads = numThreads return item }; _allInInbox = (usageCount, numThreads) => { const {account} = this.props const inbox = CategoryStore.getStandardCategory(account, "inbox") if (!inbox) return false return usageCount[inbox.id] === numThreads }; _categoryUsageCount = (props) => { const {threads} = props const categoryUsageCount = {} _.flatten(_.pluck(threads, 'categories')).forEach((category) => { categoryUsageCount[category.id] = categoryUsageCount[category.id] || 0 categoryUsageCount[category.id] += 1 }) return categoryUsageCount; }; _recalculateState = (props = this.props, {searchValue = (this.state.searchValue || "")} = {}) => { const {account, threads} = props const numThreads = threads.length let categories; if (numThreads === 0) { return {categoryData: [], searchValue} } if (account.usesLabels()) { categories = this._categories } else { categories = this._standardCategories .concat([{divider: true, id: "category-divider"}]) .concat(this._userCategories) } const usageCount = this._categoryUsageCount(props, categories) const allInInbox = this._allInInbox(usageCount, numThreads) const displayData = {usageCount, numThreads} const categoryData = _.chain(categories) .filter(_.partial(this._isUserFacing, allInInbox)) .filter(_.partial(this._isInSearch, searchValue)) .map(_.partial(this._itemForCategory, displayData)) .value() if (searchValue.length > 0) { const newItemData = { searchValue: searchValue, newCategoryItem: true, id: "category-create-new", } categoryData.push(newItemData) } return {categoryData, searchValue} }; _onCategoriesChanged = (categories) => { this._categories = categories this._standardCategories = categories.filter((cat) => cat.isStandardCategory()) this._userCategories = categories.filter((cat) => cat.isUserCategory()) this.setState(this._recalculateState()) }; _onEscape = () => { Actions.closePopover() }; _onSelectCategory = (item) => { const {account, threads} = this.props if (threads.length === 0) return; if (item.newCategoryItem) { const category = new Category({ displayName: this.state.searchValue, accountId: account.id, }) const syncbackTask = new SyncbackCategoryTask({category}) TaskQueueStatusStore.waitForPerformRemote(syncbackTask).then(() => { DatabaseStore.findBy(category.constructor, {clientId: category.clientId}) .then((cat) => { if (!cat) { const categoryType = account.usesLabels() ? "label" : "folder"; NylasEnv.showErrorDialog({title: "Error", message: `Could not create ${categoryType}.`}) return; } Actions.applyCategoryToThreads({ source: "Category Picker: New Category", threads: threads, categoryToApply: cat, }) }) }) Actions.queueTask(syncbackTask) } else if (item.usage === threads.length) { Actions.removeCategoryFromThreads({ source: "Category Picker: Existing Category", threads: threads, categoryToRemove: item.category, }) } else { Actions.applyCategoryToThreads({ source: "Category Picker: Existing Category", threads: threads, categoryToApply: item.category, }) } if (account.usesFolders()) { // In case we are drilled down into a message Actions.popSheet() } Actions.closePopover() }; _onSearchValueChange = (event) => { this.setState( this._recalculateState(this.props, {searchValue: event.target.value}) ) }; _renderFolderIcon = (item) => { return ( ) }; _renderCheckbox = (item) => { const styles = {} let checkStatus; styles.backgroundColor = item.backgroundColor if (item.usage === 0) { checkStatus = } else if (item.usage < item.numThreads) { checkStatus = ( this._onSelectCategory(item)} /> ) } else { checkStatus = ( this._onSelectCategory(item)} /> ) } return (
this._onSelectCategory(item)} /> {checkStatus}
) }; _renderCreateNewItem = ({searchValue}) => { const {account} = this.props let picName = '' if (account) { picName = account.usesLabels() ? 'tag' : 'folder' } return (
“{searchValue}” (create new)
) }; _renderItem = (item) => { if (item.divider) { return } else if (item.newCategoryItem) { return this._renderCreateNewItem(item) } const {account} = this.props let icon; if (account) { icon = account.usesLabels() ? this._renderCheckbox(item) : this._renderFolderIcon(item); } else { return } return (
{icon}
) }; render() { const {account} = this.props let placeholder = '' if (account) { placeholder = account.usesLabels() ? 'Label as' : 'Move to folder' } const headerComponents = [ , ] return (
item.id} itemContent={this._renderItem} onSelect={this._onSelectCategory} onEscape={this._onEscape} defaultSelectedIndex={this.state.searchValue === "" ? -1 : 0} />
) } } ================================================ FILE: packages/client-app/internal_packages/category-picker/lib/category-picker.cjsx ================================================ _ = require 'underscore' React = require 'react' ReactDOM = require 'react-dom' {Actions, AccountStore, WorkspaceStore} = require 'nylas-exports' {RetinaImg, KeyCommandsRegion} = require 'nylas-component-kit' CategoryPickerPopover = require('./category-picker-popover').default # This changes the category on one or more threads. class CategoryPicker extends React.Component @displayName: "CategoryPicker" @containerRequired: false @propTypes: items: React.PropTypes.array @contextTypes: sheetDepth: React.PropTypes.number constructor: (@props) -> @_account = AccountStore.accountForItems(@props.items) # If the threads we're picking categories for change, (like when they # get their categories updated), we expect our parents to pass us new # props. We don't listen to the DatabaseStore ourselves. componentWillReceiveProps: (nextProps) -> @_account = AccountStore.accountForItems(nextProps.items) _keymapHandlers: -> "core:change-category": @_onOpenCategoryPopover _onOpenCategoryPopover: => return unless @props.items.length > 0 return unless @context.sheetDepth is WorkspaceStore.sheetStack().length - 1 buttonRect = ReactDOM.findDOMNode(@refs.button).getBoundingClientRect() Actions.openPopover( , {originRect: buttonRect, direction: 'down'} ) return render: => return unless @_account btnClasses = "btn btn-toolbar btn-category-picker" img = "" tooltip = "" if @_account.usesLabels() img = "toolbar-tag.png" tooltip = "Apply Labels" else img = "toolbar-movetofolder.png" tooltip = "Move to Folder" return ( ) module.exports = CategoryPicker ================================================ FILE: packages/client-app/internal_packages/category-picker/lib/main.cjsx ================================================ CategoryPicker = require "./category-picker" {ComponentRegistry, WorkspaceStore} = require 'nylas-exports' module.exports = activate: (@state={}) -> ComponentRegistry.register CategoryPicker, role: 'ThreadActionsToolbarButton' deactivate: -> ComponentRegistry.unregister(CategoryPicker) ================================================ FILE: packages/client-app/internal_packages/category-picker/package.json ================================================ { "name": "category-picker", "version": "0.1.0", "main": "./lib/main", "description": "Label & Folder Picker", "license": "GPL-3.0", "private": true, "engines": { "nylas": "*" } } ================================================ FILE: packages/client-app/internal_packages/category-picker/spec/category-picker-spec.cjsx ================================================ _ = require 'underscore' React = require "react" ReactDOM = require 'react-dom' ReactTestUtils = require 'react-addons-test-utils' CategoryPickerPopover = require('../lib/category-picker-popover').default {Utils, Category, Thread, Actions, AccountStore, CategoryStore, DatabaseStore, TaskFactory, SyncbackCategoryTask, FocusedPerspectiveStore, MailboxPerspective, NylasTestUtils, TaskQueueStatusStore} = require 'nylas-exports' {Categories} = require 'nylas-observables' describe 'CategoryPickerPopover', -> beforeEach -> CategoryStore._categoryCache = {} afterEach -> NylasEnv.testOrganizationUnit = null setupFor = (organizationUnit) -> NylasEnv.testOrganizationUnit = organizationUnit @account = { id: TEST_ACCOUNT_ID usesLabels: -> organizationUnit is "label" usesFolders: -> organizationUnit isnt "label" } @inboxCategory = new Category(id: 'id-123', name: 'inbox', displayName: "INBOX", accountId: TEST_ACCOUNT_ID) @archiveCategory = new Category(id: 'id-456', name: 'archive', displayName: "ArCHIVe", accountId: TEST_ACCOUNT_ID) @userCategory = new Category(id: 'id-789', name: null, displayName: "MyCategory", accountId: TEST_ACCOUNT_ID) observable = NylasTestUtils.mockObservable([@inboxCategory, @archiveCategory, @userCategory]) observable.sort = => observable spyOn(Categories, "forAccount").andReturn observable spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory spyOn(AccountStore, "accountForItems").andReturn @account spyOn(Actions, "closePopover") # By default we're going to set to "inbox". This has implications for # what categories get filtered out of the list. spyOn(FocusedPerspectiveStore, 'current').andCallFake => MailboxPerspective.forCategory(@inboxCategory) setupForCreateNew = (orgUnit = "folder") -> setupFor.call(@, orgUnit) @testThread = new Thread(id: 't1', subject: "fake", accountId: TEST_ACCOUNT_ID, categories: []) @picker = ReactTestUtils.renderIntoDocument( ) describe 'when using labels', -> beforeEach -> setupFor.call(@, "label") describe 'when using folders', -> beforeEach -> setupFor.call(@, "folder") @testThread = new Thread(id: 't1', subject: "fake", accountId: TEST_ACCOUNT_ID, categories: []) @picker = ReactTestUtils.renderIntoDocument( ) it 'lists the desired categories', -> data = @picker.state.categoryData # NOTE: The inbox category is not included here because it's the # currently focused category, which gets filtered out of the list. expect(data.length).toBe 3 expect(data[0].id).toBe "id-456" expect(data[0].name).toBe "archive" expect(data[0].category).toBe @archiveCategory expect(data[1].divider).toBe true expect(data[1].id).toBe "category-divider" expect(data[2].id).toBe "id-789" expect(data[2].name).toBeUndefined() expect(data[2].category).toBe @userCategory describe "'create new' item", -> beforeEach -> setupForCreateNew.call @ afterEach -> NylasEnv.testOrganizationUnit = null it "is not visible when the search box is empty", -> count = ReactTestUtils.scryRenderedDOMComponentsWithClass(@picker, 'category-create-new').length expect(count).toBe 0 it "is visible when the search box has text", -> inputNode = ReactDOM.findDOMNode(ReactTestUtils.scryRenderedDOMComponentsWithTag(@picker, "input")[0]) ReactTestUtils.Simulate.change inputNode, target: { value: "calendar" } count = ReactTestUtils.scryRenderedDOMComponentsWithClass(@picker, 'category-create-new').length expect(count).toBe 1 it "shows folder icon if we're using exchange", -> inputNode = ReactDOM.findDOMNode(ReactTestUtils.scryRenderedDOMComponentsWithTag(@picker, "input")[0]) ReactTestUtils.Simulate.change inputNode, target: { value: "calendar" } count = ReactTestUtils.scryRenderedDOMComponentsWithClass(@picker, 'category-create-new-folder').length expect(count).toBe 1 describe "'create new' item with labels", -> beforeEach -> setupForCreateNew.call @, "label" it "shows label icon if we're using gmail", -> inputNode = ReactDOM.findDOMNode(ReactTestUtils.scryRenderedDOMComponentsWithTag(@picker, "input")[0]) ReactTestUtils.Simulate.change inputNode, target: { value: "calendar" } count = ReactTestUtils.scryRenderedDOMComponentsWithClass(@picker, 'category-create-new-tag').length expect(count).toBe 1 describe "_onSelectCategory", -> beforeEach -> setupForCreateNew.call @, "folder" spyOn(Actions, "applyCategoryToThreads") spyOn(Actions, "removeCategoryFromThreads") spyOn(Actions, "queueTask") spyOn(Actions, "queueTasks") it "closes the popover", -> @picker._onSelectCategory { usage: 0, category: "asdf" } expect(Actions.closePopover).toHaveBeenCalled() describe "when selecting a category currently on all the selected items", -> it "fires a task to remove the category", -> input = category: "asdf" usage: 1 @picker._onSelectCategory(input) expect(Actions.removeCategoryFromThreads).toHaveBeenCalledWith threads: [@testThread] source: 'Category Picker: Existing Category' categoryToRemove: "asdf" describe "when selecting a category not on all the selected items", -> it "fires a task to add the category", -> input = category: "asdf" usage: 0 @picker._onSelectCategory(input) expect(Actions.applyCategoryToThreads).toHaveBeenCalledWith source: 'Category Picker: Existing Category' threads: [@testThread] categoryToApply: "asdf" describe "when selecting a new category", -> beforeEach -> @input = newCategoryItem: true @picker.setState(searchValue: "teSTing!") it "queues a new syncback task for creating a category", -> @picker._onSelectCategory(@input) expect(Actions.queueTask).toHaveBeenCalled() syncbackTask = Actions.queueTask.calls[0].args[0] newCategory = syncbackTask.category expect(newCategory instanceof Category).toBe(true) expect(newCategory.displayName).toBe "teSTing!" expect(newCategory.accountId).toBe TEST_ACCOUNT_ID it "queues a task for applying the category after it has saved", -> category = false resolveSave = false spyOn(TaskQueueStatusStore, "waitForPerformRemote").andCallFake (task) -> expect(task instanceof SyncbackCategoryTask).toBe true new Promise (resolve, reject) -> resolveSave = resolve spyOn(DatabaseStore, "findBy").andCallFake (klass, {clientId}) -> expect(klass).toBe(Category) expect(typeof clientId).toBe("string") Promise.resolve(category) @picker._onSelectCategory(@input) waitsFor -> Actions.queueTask.callCount > 0 runs -> category = Actions.queueTask.calls[0].args[0].category resolveSave() waitsFor -> Actions.applyCategoryToThreads.calls.length is 1 runs -> expect(Actions.applyCategoryToThreads).toHaveBeenCalledWith source: 'Category Picker: New Category' threads: [@testThread] categoryToApply: category ================================================ FILE: packages/client-app/internal_packages/category-picker/stylesheets/category-picker.less ================================================ @import "ui-variables"; @popover-width: 250px; body.platform-win32 { .category-picker-popover { margin-left: 0; } } .sheet-toolbar .btn-category-picker:only-of-type { margin-right: 0; } .category-picker-popover { .menu { background: @background-secondary; width: @popover-width; max-height: 400px; .header-container { border-bottom: 0; } .item.divider { background-color: #e0e0e0; margin: 4px 0; height: 2px; padding: 0; } } .btn.btn-toolbar { margin-left: 0; margin-right: 0; } .check-wrap { width: 14px; height: 14px; border-radius: 2px; display: inline-block; position: relative; flex-shrink: 0; top: 2px; } .item { img.content-mask { position: relative; top:3px; background-color: @text-color-subtle; } } .item.selected, .item.active { img.content-mask { background-color: @text-color-inverse; } } img.check-img { position: absolute; } .category-item { font-size: 14px; display: flex; } .category-create-new-tag { flex-shrink: 0; } .category-display-name { display: inline-block; margin-left: 10px; margin-right: 5px; word-break: break-word; flex: 1; } } ================================================ FILE: packages/client-app/internal_packages/composer/README.md ================================================ # composer package ================================================ FILE: packages/client-app/internal_packages/composer/keymaps/composer.json ================================================ { "composer:focus-to": "mod+shift+t", "composer:show-and-focus-cc": "mod+shift+c", "composer:show-and-focus-bcc": "mod+shift+b", "composer:show-and-focus-from": "mod+shift+f", "composer:send-message": "mod+enter", "composer:no-op": "del", "composer:delete-empty-draft": "escape" } ================================================ FILE: packages/client-app/internal_packages/composer/lib/account-contact-field.jsx ================================================ import React from 'react'; import classnames from 'classnames'; import { AccountStore, } from 'nylas-exports'; import {Menu, ButtonDropdown, InjectedComponentSet} from 'nylas-component-kit'; export default class AccountContactField extends React.Component { static displayName = 'AccountContactField'; static propTypes = { value: React.PropTypes.object, accounts: React.PropTypes.array, session: React.PropTypes.object.isRequired, draft: React.PropTypes.object.isRequired, onChange: React.PropTypes.func.isRequired, }; _onChooseContact = (contact) => { this.props.onChange({from: [contact]}); this.props.session.ensureCorrectAccount() this.refs.dropdown.toggleDropdown(); } _renderAccountSelector() { if (!this.props.value) { return ( ); } const label = this.props.value.toString(); const multipleAccounts = this.props.accounts.length > 1; const hasAliases = this.props.accounts[0] && this.props.accounts[0].aliases.length > 0; if (multipleAccounts || hasAliases) { return ( {label}} menu={this._renderAccounts(this.props.accounts)} /> ); } return this._renderAccountSpan(label); } _renderAccountSpan = (label) => { return ( {label} ); } _renderMenuItem = (contact) => { const className = classnames({ 'contact': true, 'is-alias': contact.isAlias, }); return ( {contact.toString()} ); } _renderAccounts(accounts) { const items = AccountStore.aliasesFor(accounts); return ( contact.id} itemContent={this._renderMenuItem} onSelect={this._onChooseContact} /> ); } _renderFromFieldComponents = () => { const {draft, session, accounts} = this.props return ( ) } render() { return (
From:
{this._renderAccountSelector()} {this._renderFromFieldComponents()}
); } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/action-bar-plugins.jsx ================================================ import React from 'react' import classnames from 'classnames' import {ComponentRegistry} from 'nylas-exports' import {InjectedComponentSet} from 'nylas-component-kit' const ROLE = "Composer:ActionButton"; export default class ActionBarPlugins extends React.Component { static displayName = "ActionBarPlugins"; static propTypes = { draft: React.PropTypes.object, session: React.PropTypes.object, isValidDraft: React.PropTypes.func, } constructor(props) { super(props); this.state = this._getStateFromStores() } componentDidMount() { this._usub = ComponentRegistry.listen(this._onComponentsChange) } componentWillUnmount() { this._usub(); } _onComponentsChange = () => { if (this._getPluginsLength() > 0) { // The `InjectedComponentSet` also listens to the ComponentRegistry. // Since we can't guarantee the order the listeners are fired in and // we want to make sure we add the class after the injected component // set has rendered, put the call in this requestAnimationFrame // // It also takes 2 frames to reliably get all of the icons painted. window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { this.setState(this._getStateFromStores()) }) }) } } _getPluginsLength() { return ComponentRegistry.findComponentsMatching({role: ROLE}).length; } _getStateFromStores() { return { pluginsLoaded: this._getPluginsLength() > 0, } } render() { const className = classnames({ "action-bar-animation-wrap": true, "plugins-loaded": this.state.pluginsLoaded, }); return (
) } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/collapsed-participants.jsx ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import {Utils} from 'nylas-exports'; import {DropZone, InjectedComponentSet} from 'nylas-component-kit'; const NUM_TO_DISPLAY_MAX = 999; export default class CollapsedParticipants extends React.Component { static displayName = "CollapsedParticipants"; static propTypes = { // Arrays of Contact objects. to: React.PropTypes.array, cc: React.PropTypes.array, bcc: React.PropTypes.array, onDrop: React.PropTypes.func, onDragChange: React.PropTypes.func, } static defaultProps = { to: [], cc: [], bcc: [], onDrop: () => {}, onDragChange: () => {}, } constructor(props = {}) { super(props); this.state = { numToDisplay: NUM_TO_DISPLAY_MAX, numRemaining: 0, numBccRemaining: 0, } } componentDidMount() { this._setNumHiddenParticipants(); } componentWillReceiveProps(nextProps) { if (!Utils.isEqualReact(nextProps, this.props)) { // Always re-evaluate the hidden participant count when the participant set changes this.setState({ numToDisplay: NUM_TO_DISPLAY_MAX, numRemaining: 0, numBccRemaining: 0, }); } } shouldComponentUpdate(nextProps, nextState) { return !Utils.isEqualReact(nextProps, this.props) || !Utils.isEqualReact(nextState, this.state); } componentDidUpdate() { if (this.state.numToDisplay === NUM_TO_DISPLAY_MAX) { this._setNumHiddenParticipants(); } } _setNumHiddenParticipants() { const $wrap = ReactDOM.findDOMNode(this.refs.participantsWrap); const $regulars = Array.from($wrap.getElementsByClassName("regular-contact")); const $bccs = Array.from($wrap.getElementsByClassName("bcc-contact")); const availableSpace = $wrap.getBoundingClientRect().width; let numRemaining = this.props.to.length + this.props.cc.length; let numBccRemaining = this.props.bcc.length; let numToDisplay = 0; let widthAccumulator = 0; for (const $p of $regulars) { widthAccumulator += $p.getBoundingClientRect().width; if (widthAccumulator >= availableSpace) { break; } numRemaining -= 1; numToDisplay += 1; } for (const $p of $bccs) { widthAccumulator += $p.getBoundingClientRect().width; if (widthAccumulator >= availableSpace) { break; } numBccRemaining -= 1; numToDisplay += 1; } this.setState({numToDisplay, numRemaining, numBccRemaining}); } _renderNumRemaining() { let str = null; if (this.state.numRemaining === 0 && this.state.numBccRemaining === 0) { return null; } else if (this.state.numRemaining > 0 && this.state.numBccRemaining === 0) { str = `${this.state.numRemaining} more`; } else if (this.state.numRemaining === 0 && this.state.numBccRemaining > 0) { str = `${this.state.numBccRemaining} Bcc`; } else if (this.state.numRemaining > 0 && this.state.numBccRemaining > 0) { str = `${this.state.numRemaining + this.state.numBccRemaining} more (${this.state.numBccRemaining} Bcc)`; } return (
{str}
); } _collapsedContact = (contact) => { const name = contact.displayName(); const key = contact.email + contact.name; return ( {name} ); } _collapsedBccContact = (contact, i) => { let name = contact.displayName(); const key = contact.email + contact.name; if (i === 0) { name = `Bcc: ${name}`; } return ( {name} ); } render() { const contacts = this.props.to.concat(this.props.cc).map(this._collapsedContact) const bcc = this.props.bcc.map(this._collapsedBccContact); let toDisplay = contacts.concat(bcc); toDisplay = toDisplay.splice(0, this.state.numToDisplay); if (toDisplay.length === 0) { toDisplay = "Recipients"; } return ( true} onDragStateChange={this.props.onDragChange} onDrop={this.props.onDrop} >
{this._renderNumRemaining()} {toDisplay}
); } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/compose-button.jsx ================================================ import React from 'react'; import {Actions} from 'nylas-exports'; import {RetinaImg} from 'nylas-component-kit'; export default class ComposeButton extends React.Component { static displayName = 'ComposeButton'; _onNewCompose = () => { Actions.composeNewBlankDraft() } render() { return ( ); } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/composer-editor.jsx ================================================ import React, {Component, PropTypes} from 'react'; import {ExtensionRegistry, DOMUtils} from 'nylas-exports'; import {DropZone, ScrollRegion, Contenteditable} from 'nylas-component-kit'; /** * Renders the text editor for the composer * Any component registering in the ComponentRegistry with the role * 'Composer:Editor' will receive these set of props. * * In order for the Composer to work correctly and have a complete set of * functionality (like file pasting), any registered editor *must* call the * provided callbacks at the appropriate time. * * @param {object} props - props for ComposerEditor * @param {string} props.body - Html string with the draft content to be * rendered by the editor * @param {string} props.draftClientId - Id of the draft being currently edited * @param {object} props.parentActions - Object containg helper actions * associated with the parent container * @param {props.parentActions.getComposerBoundingRect} props.parentActions.getComposerBoundingRect * @param {props.parentActions.scrollTo} props.parentActions.scrollTo * @param {props.onFilePaste} props.onFilePaste * @param {props.onBodyChanged} props.onBodyChanged * @class ComposerEditor */ const NODE_END = false; const NODE_BEGINNING = true; class ComposerEditor extends Component { static displayName = 'ComposerEditor'; /** * This function will return the {DOMRect} for the parent component * @function * @name props.parentActions.getComposerBoundingRect */ /** * This function will make the screen scrollTo the desired position in the * message list * @function * @name props.parentActions.scrollTo * @param {object} options * @param {string} options.clientId - Id of the message we want to scroll to * @param {string} [options.positon] - If clientId is provided, this optional * parameter will indicate what position of the message to scrollTo. See * {ScrollRegion} * @param {DOMRect} options.rect - Bounding rect we want to scroll to */ /** * This function should be called when the user pastes a file into the editing * region * @callback props.onFilePaste */ /** * This function should be called when the body of the draft changes, i.e. * when the editor is being typed into. It should pass in an object that looks * like a DOM Event with the current value of the content. * @callback props.onBodyChanged * @param {object} event - DOMEvent-like object that contains information * about the current value of the body * @param {string} event.target.value - HTML string that represents the * current content of the editor body */ static propTypes = { body: PropTypes.string.isRequired, draftClientId: PropTypes.string, onFilePaste: PropTypes.func, onBodyChanged: PropTypes.func, parentActions: PropTypes.shape({ scrollTo: PropTypes.func, getComposerBoundingRect: PropTypes.func, }), }; constructor(props) { super(props); this.state = { extensions: ExtensionRegistry.Composer.extensions(), }; } componentDidMount() { this.unsub = ExtensionRegistry.Composer.listen(this._onExtensionsChanged); } componentWillUnmount() { this.unsub(); } // Public methods // TODO Get rid of these selection methods getCurrentSelection() { return this.refs.contenteditable.getCurrentSelection(); } getPreviousSelection() { return this.refs.contenteditable.getPreviousSelection(); } setSelection(selection) { this.refs.contenteditable.setSelection(selection); } focus() { // focus the composer and place the insertion point at the last text node of // the body. Be sure to choose the last node /above/ the signature and any // quoted text that is visible. (as in forwarded messages.) // this.refs.contenteditable.atomicEdit(({editor}) => { editor.rootNode.focus(); const lastNode = this._findLastNodeBeforeQuoteOrSignature(editor) if (lastNode) { this._selectNode(lastNode, {collapseTo: NODE_END}); } else { this._selectNode(editor.rootNode, {collapseTo: NODE_BEGINNING}); } }); } focusAbsoluteEnd() { this.refs.contenteditable.atomicEdit(({editor}) => { editor.rootNode.focus(); this._selectNode(editor.rootNode, {collapseTo: NODE_END}); }); } // Note: This method returns null for new drafts, because the leading //
tags contain no text nodes. _findLastNodeBeforeQuoteOrSignature(editor) { const walker = document.createTreeWalker(editor.rootNode, NodeFilter.SHOW_TEXT); const nodesBelowUserBody = editor.rootNode.querySelectorAll('signature, .gmail_quote, blockquote'); let lastNode = null; let node = walker.nextNode(); while (node != null) { let belowUserBody = false; for (let i = 0; i < nodesBelowUserBody.length; ++i) { if (nodesBelowUserBody[i].contains(node)) { belowUserBody = true; break; } } if (belowUserBody) { break; } lastNode = node; node = walker.nextNode(); } return lastNode } _selectNode(node, {collapseTo} = {}) { const range = document.createRange(); range.selectNodeContents(node); range.collapse(collapseTo); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); } /** * @private * This method was included so that the tests don't break * TODO refactor the tests! */ _onDOMMutated(mutations) { this.refs.contenteditable._onDOMMutated(mutations); } _onDrop = (event) => { this.refs.contenteditable._onDrop(event) } _onDragOver = (event) => { this.refs.contenteditable._onDragOver(event) } _shouldAcceptDrop = (event) => { return this.refs.contenteditable._shouldAcceptDrop(event) } // Helpers _scrollToBottom = () => { this.props.parentActions.scrollTo({ clientId: this.props.draftClientId, position: ScrollRegion.ScrollPosition.Bottom, }); }; /** * @private * If the bottom of the container we're scrolling to is really far away * from the contenteditable and your scroll position, we don't want to * jump away. This can commonly happen if the composer has a very tall * image attachment. The "send" button may be 1000px away from the bottom * of the contenteditable. props.parentActions.scrollToBottom moves to the bottom of * the "send" button. */ _bottomIsNearby = (editableNode) => { const parentRect = this.props.parentActions.getComposerBoundingRect(); const selfRect = editableNode.getBoundingClientRect(); return Math.abs(parentRect.bottom - selfRect.bottom) <= 250; }; /** * @private * As you're typing a lot of content and the cursor begins to scroll off * to the bottom, we want to make it look like we're tracking your * typing. */ _shouldScrollToBottom(selection, editableNode) { return ( this.props.parentActions.scrollTo != null && DOMUtils.atEndOfContent(selection, editableNode) && this._bottomIsNearby(editableNode) ); } /** * @private * When the selectionState gets set (e.g. undo-ing and * redo-ing) we need to make sure it's visible to the user. * * Unfortunately, we can't use the native `scrollIntoView` because it * naively scrolls the whole window and doesn't know not to scroll if * it's already in view. There's a new native method called * `scrollIntoViewIfNeeded`, but this only works when the scroll * container is a direct parent of the requested element. In this case * the scroll container may be many levels up. */ _ensureSelectionVisible = (selection, editableNode) => { // If our parent supports scroll, check for that if (this._shouldScrollToBottom(selection, editableNode)) { this._scrollToBottom(); } else if (this.props.parentActions.scrollTo != null) { // Don't bother computing client rects if no scroll method has been provided const rangeInScope = DOMUtils.getRangeInScope(editableNode); if (!rangeInScope) return; let rect = rangeInScope.getBoundingClientRect(); if (DOMUtils.isEmptyBoundingRect(rect)) { rect = DOMUtils.getSelectionRectFromDOM(selection); } if (rect) { this.props.parentActions.scrollTo({rect}); } } }; // Handlers _onExtensionsChanged = () => { this.setState({extensions: ExtensionRegistry.Composer.extensions()}); }; // Renderers render() { return ( ); } } ComposerEditor.containerRequired = false export default ComposerEditor; ================================================ FILE: packages/client-app/internal_packages/composer/lib/composer-header-actions.jsx ================================================ import React from 'react'; import {Actions} from 'nylas-exports'; import {RetinaImg} from 'nylas-component-kit'; import Fields from './fields'; export default class ComposerHeaderActions extends React.Component { static displayName = 'ComposerHeaderActions'; static propTypes = { draftClientId: React.PropTypes.string.isRequired, enabledFields: React.PropTypes.array.isRequired, participantsFocused: React.PropTypes.bool, onShowAndFocusField: React.PropTypes.func.isRequired, } _onPopoutComposer = () => { Actions.composePopoutDraft(this.props.draftClientId); } render() { const items = []; if (this.props.participantsFocused) { if (!this.props.enabledFields.includes(Fields.Cc)) { items.push( this.props.onShowAndFocusField(Fields.Cc)} >Cc ); } if (!this.props.enabledFields.includes(Fields.Bcc)) { items.push( this.props.onShowAndFocusField(Fields.Bcc)} >Bcc ); } } if (!this.props.enabledFields.includes(Fields.Subject)) { items.push( this.props.onShowAndFocusField(Fields.Subject)} >Subject ); } if (!NylasEnv.isComposerWindow()) { items.push( ); } return (
{items}
); } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/composer-header.jsx ================================================ import _ from 'underscore'; import React from 'react'; import ReactDOM from 'react-dom'; import {Utils, DraftHelpers, Actions, AccountStore} from 'nylas-exports'; import { InjectedComponent, KeyCommandsRegion, ParticipantsTextField, ListensToFluxStore, } from 'nylas-component-kit'; import AccountContactField from './account-contact-field'; import CollapsedParticipants from './collapsed-participants'; import ComposerHeaderActions from './composer-header-actions'; import SubjectTextField from './subject-text-field'; import Fields from './fields'; const ScopedFromField = ListensToFluxStore(AccountContactField, { stores: [AccountStore], getStateFromStores: (props) => { const savedOrReplyToThread = !!props.draft.threadId; if (savedOrReplyToThread) { return {accounts: [AccountStore.accountForId(props.draft.accountId)]}; } return {accounts: AccountStore.accounts()} }, }); export default class ComposerHeader extends React.Component { static displayName = "ComposerHeader"; static propTypes = { draft: React.PropTypes.object.isRequired, session: React.PropTypes.object.isRequired, initiallyFocused: React.PropTypes.bool, // Subject text field injected component needs to call this function // when it is rendered with a new header component onNewHeaderComponents: React.PropTypes.func, } static contextTypes = { parentTabGroup: React.PropTypes.object, } constructor(props = {}) { super(props) this.state = this._initialStateForDraft(this.props.draft, props); } componentWillReceiveProps(nextProps) { if (this.props.session !== nextProps.session) { this.setState(this._initialStateForDraft(nextProps.draft, nextProps)); } else { this._ensureFilledFieldsEnabled(nextProps.draft); } } focus() { if (this.state.subjectFocused) { this.refs.subject.focus(); } else if (this.state.participantsFocused) { this.showAndFocusField(Fields.To); } console.warn("Nothing is marked as focused. This shouldn't happen!"); this.showAndFocusField(Fields.To); } showAndFocusField = (fieldName) => { const enabledFields = _.uniq([].concat(this.state.enabledFields, [fieldName])); const participantsFocused = this.state.participantsFocused || Fields.ParticipantFields.includes(fieldName); Utils.waitFor(() => this.refs[fieldName]).then(() => this.refs[fieldName].focus() ).catch(() => { }) this.setState({enabledFields, participantsFocused}); } hideField = (fieldName) => { if (ReactDOM.findDOMNode(this.refs[fieldName]).contains(document.activeElement)) { this.context.parentTabGroup.shiftFocus(-1) } const enabledFields = _.without(this.state.enabledFields, fieldName) this.setState({enabledFields}) } _ensureFilledFieldsEnabled(draft) { let enabledFields = this.state.enabledFields; if (!_.isEmpty(draft.cc)) { enabledFields = enabledFields.concat([Fields.Cc]); } if (!_.isEmpty(draft.bcc)) { enabledFields = enabledFields.concat([Fields.Bcc]); } if (enabledFields !== this.state.enabledFields) { this.setState({enabledFields}); } } _initialStateForDraft(draft, props) { const enabledFields = [Fields.To]; if (!_.isEmpty(draft.cc)) { enabledFields.push(Fields.Cc); } if (!_.isEmpty(draft.bcc)) { enabledFields.push(Fields.Bcc); } enabledFields.push(Fields.From); if (this._shouldEnableSubject()) { enabledFields.push(Fields.Subject); } return { enabledFields, participantsFocused: props.initiallyFocused, subjectFocused: false, }; } _shouldEnableSubject = () => { if (_.isEmpty(this.props.draft.subject)) { return true; } if (DraftHelpers.isForwardedMessage(this.props.draft)) { return true; } if (this.props.draft.replyToMessageId) { return false; } return true; } _onChangeParticipants = (changes) => { this.props.session.changes.add(changes); Actions.draftParticipantsChanged(this.props.draft.clientId, changes); } _onSubjectChange = (value) => { this.props.session.changes.add({subject: value}); } _onFocusInParticipants = () => { const fieldName = this.state.participantsLastActiveField || Fields.To; Utils.waitFor(() => this.refs[fieldName] ).then(() => this.refs[fieldName].focus() ).catch(() => { }); this.setState({ participantsFocused: true, participantsLastActiveField: null, }); } _onFocusOutParticipants = (lastFocusedEl) => { const active = Fields.ParticipantFields.find((fieldName) => { return this.refs[fieldName] ? ReactDOM.findDOMNode(this.refs[fieldName]).contains(lastFocusedEl) : false } ); this.setState({ participantsFocused: false, participantsLastActiveField: active, }); } _onFocusInSubject = () => { this.setState({ subjectFocused: true, }); } _onFocusOutSubject = () => { this.setState({ subjectFocused: false, }); } isFocused() { return this.state.participantsFocused || this.state.subjectFocused; } _onDragCollapsedParticipants = ({isDropping}) => { if (isDropping) { this.setState({ participantsFocused: true, enabledFields: [...Fields.ParticipantFields, Fields.From, Fields.Subject], }) } } _renderParticipants = () => { let content = null; if (this.state.participantsFocused) { content = this._renderFields(); } else { content = ( ) } // When the participants field collapses, we store the field that was last // focused onto our state, so that we can restore focus to it when the fields // are expanded again. return ( {content} ); } _renderSubject = () => { if (!this.state.enabledFields.includes(Fields.Subject)) { return false; } const {draft, session} = this.props return ( ) } _renderFields = () => { const {to, cc, bcc, from} = this.props.draft; // Note: We need to physically add and remove these elements, not just hide them. // If they're hidden, shift-tab between fields breaks. const fields = []; fields.push( ) if (this.state.enabledFields.includes(Fields.Cc)) { fields.push( this.hideField(Fields.Cc)} className="composer-participant-field cc-field" participants={{to, cc, bcc}} draft={this.props.draft} session={this.props.session} /> ) } if (this.state.enabledFields.includes(Fields.Bcc)) { fields.push( this.hideField(Fields.Bcc)} className="composer-participant-field bcc-field" participants={{to, cc, bcc}} draft={this.props.draft} session={this.props.session} /> ) } if (this.state.enabledFields.includes(Fields.From)) { fields.push( ) } return fields; } render() { return (
{this._renderParticipants()} {this._renderSubject()}
) } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/composer-view.jsx ================================================ import React from 'react' import ReactDOM from 'react-dom' import {remote} from 'electron' import { Utils, Actions, DraftStore, DraftHelpers, } from 'nylas-exports' import { DropZone, RetinaImg, ScrollRegion, TabGroupRegion, AttachmentItem, InjectedComponent, KeyCommandsRegion, OverlaidComponents, ImageAttachmentItem, InjectedComponentSet, } from 'nylas-component-kit' import ComposerEditor from './composer-editor' import ComposerHeader from './composer-header' import SendActionButton from './send-action-button' import ActionBarPlugins from './action-bar-plugins' import Fields from './fields' // The ComposerView is a unique React component because it (currently) is a // singleton. Normally, the React way to do things would be to re-render the // Composer with new props. export default class ComposerView extends React.Component { static displayName = 'ComposerView'; static propTypes = { session: React.PropTypes.object.isRequired, draft: React.PropTypes.object.isRequired, // Sometimes when changes in the composer happens it's desirable to // have the parent scroll to a certain location. A parent component can // pass a callback that gets called when this composer wants to be // scrolled to. scrollTo: React.PropTypes.func, className: React.PropTypes.string, } constructor(props) { super(props) this.state = { showQuotedText: DraftHelpers.isForwardedMessage(props.draft), showQuotedTextControl: DraftHelpers.shouldAppendQuotedText(props.draft), } } componentDidMount() { this._recordComposerOpenTime() if (this.props.session) { this._setupForProps(this.props); } } componentWillReceiveProps(nextProps) { if (nextProps.session !== this.props.session) { this._teardownForProps(); this._setupForProps(nextProps); } if (DraftHelpers.isForwardedMessage(this.props.draft) !== DraftHelpers.isForwardedMessage(nextProps.draft) || DraftHelpers.shouldAppendQuotedText(this.props.draft) !== DraftHelpers.shouldAppendQuotedText(nextProps.draft)) { this.setState({ showQuotedText: DraftHelpers.isForwardedMessage(nextProps.draft), showQuotedTextControl: DraftHelpers.shouldAppendQuotedText(nextProps.draft), }); } } componentWillUnmount() { this._teardownForProps(); } focus() { if (this.refs.header.isFocused()) { this.refs.header.focus(); } else { this.refs[Fields.Body].focus(); } } _recordComposerOpenTime() { const {draft: {threadId, replyToMessageId}} = this.props if (NylasEnv.isComposerWindow()) { return } // This method only records inline composer opening times. Composer window // opening times are recorded in ComposerWithWindowPros const replyTimerKey = `compose-reply-${replyToMessageId}` const forwardTimerKey = `compose-forward-${threadId}` let actionTimeMs; if (NylasEnv.timer.isPending(replyTimerKey)) { actionTimeMs = NylasEnv.timer.stop(replyTimerKey) } if (NylasEnv.timer.isPending(forwardTimerKey)) { actionTimeMs = NylasEnv.timer.stop(forwardTimerKey) } if (actionTimeMs != null) { Actions.recordPerfMetric({ action: 'open-inline-composer', actionTimeMs, maxValue: 4000, sample: 0.9, }) } } _keymapHandlers() { return { 'composer:send-message': () => this._onPrimarySend(), 'composer:delete-empty-draft': () => { if (this.props.draft.pristine) { this._onDestroyDraft(); } }, 'composer:show-and-focus-bcc': () => this.refs.header.showAndFocusField(Fields.Bcc), 'composer:show-and-focus-cc': () => this.refs.header.showAndFocusField(Fields.Cc), 'composer:focus-to': () => this.refs.header.showAndFocusField(Fields.To), "composer:show-and-focus-from": () => {}, "core:undo": (event) => { event.preventDefault(); event.stopPropagation(); this.props.session.undo(); }, "core:redo": (event) => { event.preventDefault(); event.stopPropagation(); this.props.session.redo(); }, }; } _setupForProps({draft, session}) { this.setState({ showQuotedText: DraftHelpers.isForwardedMessage(draft), showQuotedTextControl: DraftHelpers.shouldAppendQuotedText(draft), }); // TODO: This is a dirty hack to save selection state into the undo/redo // history. Remove it if / when selection is written into the body with // marker tags, or when selection is moved from `contenteditable.innerState` // into a first-order part of the session state. session._composerViewSelectionRetrieve = () => { // Selection updates /before/ the contenteditable emits it's change event, // so the selection that goes with the snapshot state is the previous one. if (this.refs[Fields.Body].getPreviousSelection) { return this.refs[Fields.Body].getPreviousSelection(); } return null; } session._composerViewSelectionRestore = (selection) => { this.refs[Fields.Body].setSelection(selection); } draft.files.forEach((file) => { if (Utils.shouldDisplayAsImage(file)) { Actions.fetchFile(file); } }); } _teardownForProps() { if (this.props.session) { this.props.session._composerViewSelectionRestore = null; this.props.session._composerViewSelectionRetrieve = null; } } _renderContentScrollRegion() { if (NylasEnv.isComposerWindow()) { return ( {this._renderContent()} ); } return this._renderContent(); } _onNewHeaderComponents = () => { if (this.refs.header) { this.focus() } } _renderContent() { return (
{this._renderBodyRegions()} {this._renderFooterRegions()}
); } _renderBodyRegions() { const exposedProps = { draft: this.props.draft, session: this.props.session, } return (
{this._renderEditor()} {this._renderQuotedTextControl()} {this._renderAttachments()}
); } _renderEditor() { const exposedProps = { body: this.props.draft.body, draftClientId: this.props.draft.clientId, parentActions: { getComposerBoundingRect: this._getComposerBoundingRect, scrollTo: this.props.scrollTo, }, onFilePaste: this._onFileReceived, onBodyChanged: this._onBodyChanged, }; return ( ); } // The contenteditable decides when to request a scroll based on the // position of the cursor and its relative distance to this composer // component. We provide it our boundingClientRect so it can calculate // this value. _getComposerBoundingRect = () => { return ReactDOM.findDOMNode(this.refs.composerWrap).getBoundingClientRect() } _renderQuotedTextControl() { if (this.state.showQuotedTextControl) { return ( ••• ); } return false; } _onExpandQuotedText = () => { this.setState({ showQuotedText: true, showQuotedTextControl: false, }, () => { DraftHelpers.appendQuotedTextToDraft(this.props.draft) .then((draftWithQuotedText) => { this.props.session.changes.add({ body: `${draftWithQuotedText.body}
`, }) }) }) } _onRemoveQuotedText = (event) => { event.stopPropagation() const {session, draft} = this.props session.changes.add({ body: `${draft.body}
`, }) this.setState({ showQuotedText: false, showQuotedTextControl: false, }) } _renderFooterRegions() { return (
); } _renderAttachments() { return (
{this._renderFileAttachments()} {this._renderUploadAttachments()}
); } _renderFileAttachments() { const {files, clientId: messageClientId} = this.props.draft return ( ) } _imageFiles(files) { return files.filter(f => Utils.shouldDisplayAsImage(f)); } _nonImageFiles(files) { return files.filter(f => !Utils.shouldDisplayAsImage(f)); } _renderUploadAttachments() { const {uploads} = this.props.draft; const nonImageUploads = this._nonImageFiles(uploads) .map((upload) => Actions.removeAttachment(upload)} /> ); const imageUploads = this._imageFiles(uploads) .filter(u => !u.inline) .map((upload) => Actions.removeAttachment(upload)} /> ); return nonImageUploads.concat(imageUploads); } _renderActionsWorkspaceRegion() { return ( ) } _renderActionsRegion() { return (
); } // This lets us click outside of the `contenteditable`'s `contentBody` // and simulate what happens when you click beneath the text *in* the // contentEditable. // Unfortunately, we need to manually keep track of the "click" in // separate mouseDown, mouseUp events because we need to ensure that the // start and end target are both not in the contenteditable. This ensures // that this behavior doesn't interfear with a click and drag selection. _onMouseDownComposerBody = (event) => { if (ReactDOM.findDOMNode(this.refs[Fields.Body]).contains(event.target)) { this._mouseDownTarget = null; } else { this._mouseDownTarget = event.target; } } _inFooterRegion(el) { return el.closest && el.closest(".composer-footer-region, .overlaid-components") } _onMouseUpComposerBody = (event) => { if (event.target === this._mouseDownTarget && !this._inFooterRegion(event.target)) { // We don't set state directly here because we want the native // contenteditable focus behavior. When the contenteditable gets focused const bodyRect = ReactDOM.findDOMNode(this.refs[Fields.Body]).getBoundingClientRect() if (event.pageY < bodyRect.top) { this.refs[Fields.Body].focus() } else { this.refs[Fields.Body].focusAbsoluteEnd(); } } this._mouseDownTarget = null; } _onMouseMoveComposeBody = () => { if (this._mouseComposeBody === "down") { this._mouseComposeBody = "move"; } } _shouldAcceptDrop = (event) => { // Ensure that you can't pick up a file and drop it on the same draft const nonNativeFilePath = this._nonNativeFilePathForDrop(event); const hasNativeFile = event.dataTransfer.files.length > 0; const hasNonNativeFilePath = nonNativeFilePath !== null; return hasNativeFile || hasNonNativeFilePath; } _nonNativeFilePathForDrop = (event) => { if (event.dataTransfer.types.includes("text/nylas-file-url")) { const downloadURL = event.dataTransfer.getData("text/nylas-file-url"); const downloadFilePath = downloadURL.split('file://')[1]; if (downloadFilePath) { return downloadFilePath; } } // Accept drops of images from within the app if (event.dataTransfer.types.includes("text/uri-list")) { const uri = event.dataTransfer.getData('text/uri-list') if (uri.indexOf('file://') === 0) { return decodeURI(uri.split('file://')[1]); } } return null; } _onDrop = (event) => { // Accept drops of real files from other applications for (const file of Array.from(event.dataTransfer.files)) { this._onFileReceived(file.path); } // Accept drops from attachment components / images within the app const uri = this._nonNativeFilePathForDrop(event); if (uri) { this._onFileReceived(uri); } } _onFileReceived = (filePath) => { // called from onDrop and onFilePaste - assume images should be inline Actions.addAttachment({ filePath: filePath, messageClientId: this.props.draft.clientId, onUploadCreated: (upload) => { if (Utils.shouldDisplayAsImage(upload)) { const {draft, session} = this.props; const uploads = [].concat(draft.uploads); const matchingUpload = uploads.find(u => u.id === upload.id); if (matchingUpload) { matchingUpload.inline = true; session.changes.add({uploads}) Actions.insertAttachmentIntoDraft({ draftClientId: draft.clientId, uploadId: matchingUpload.id, }); } } }, }); } _onBodyChanged = (event) => { this.props.session.changes.add({body: event.target.value}); return; } _isValidDraft = (options = {}) => { // We need to check the `DraftStore` because the `DraftStore` is // immediately and synchronously updated as soon as this function // fires. Since `setState` is asynchronous, if we used that as our only // check, then we might get a false reading. if (DraftStore.isSendingDraft(this.props.draft.clientId)) { return false; } const dialog = remote.dialog; const {session} = this.props const {errors, warnings} = session.validateDraftForSending() if (errors.length > 0) { dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', buttons: ['Edit Message', 'Cancel'], message: 'Cannot Send', detail: errors[0], }); return false; } if ((warnings.length > 0) && (!options.force)) { const response = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', buttons: ['Send Anyway', 'Cancel'], message: 'Are you sure?', detail: `Send ${warnings.join(' and ')}?`, }); if (response === 0) { // response is button array index return this._isValidDraft({force: true}); } return false; } return true; } _onPrimarySend = () => { this.refs.sendActionButton.primarySend(); } _onDestroyDraft = () => { Actions.destroyDraft(this.props.draft.clientId); } _onSelectAttachment = () => { Actions.selectAttachment({messageClientId: this.props.draft.clientId}); } render() { const dropCoverDisplay = this.state.isDropping ? 'block' : 'none'; return (
this.setState({isDropping})} onDrop={this._onDrop} >
Drop to attach
{this._renderContentScrollRegion()}
{this._renderActionsWorkspaceRegion()}
{this._renderActionsRegion()}
); } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/fields.es6 ================================================ const Fields = { To: "textFieldTo", Cc: "textFieldCc", Bcc: "textFieldBcc", From: "fromField", Subject: "textFieldSubject", Body: "contentBody", }; Fields.ParticipantFields = [Fields.To, Fields.Cc, Fields.Bcc]; Fields.Order = { textFieldTo: 1, textFieldCc: 2, textFieldBcc: 3, fromField: -1, // Not selectable textFieldSubject: 5, contentBody: 6, }; export default Fields ================================================ FILE: packages/client-app/internal_packages/composer/lib/image-upload-composer-extension.es6 ================================================ import { Actions, ComposerExtension, } from 'nylas-exports' export default class ImageUploadComposerExtension extends ComposerExtension { static editingActions() { return [{ action: Actions.insertAttachmentIntoDraft, callback: ImageUploadComposerExtension._onInsertAttachmentIntoDraft, }, { action: Actions.removeAttachment, callback: ImageUploadComposerExtension._onRemovedAttachment, }] } static _onRemovedAttachment({editor, actionArg}) { const upload = actionArg; const el = editor.rootNode.querySelector(`.inline-container-${upload.id}`) if (el) { el.parentNode.removeChild(el); } } static _onInsertAttachmentIntoDraft({editor, actionArg}) { if (editor.draftClientId === actionArg.draftClientId) { return } editor.insertCustomComponent("InlineImageUploadContainer", { className: `inline-container-${actionArg.uploadId}`, uploadId: actionArg.uploadId, }) } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/inline-image-upload-container.jsx ================================================ import React, {Component, PropTypes} from 'react'; import ReactDOM from 'react-dom'; import fs from 'fs'; import path from 'path'; import {Actions} from 'nylas-exports' import {ImageAttachmentItem} from 'nylas-component-kit' export default class InlineImageUploadContainer extends Component { static displayName = 'InlineImageUploadContainer'; static supportsPreviewWithinEditor = false; static propTypes = { draft: PropTypes.object.isRequired, uploadId: PropTypes.string.isRequired, session: PropTypes.object, isPreview: PropTypes.bool, } _onGoEdit = () => { if (!this.props.session) { console.warn("InlineImage editor cannot be activated, `session` prop not present. (isPreview?)") return; } // This is just a fun temporary hack because I was jealous of Apple Mail. // const el = ReactDOM.findDOMNode(this); const rect = el.getBoundingClientRect(); const editorEl = document.createElement('div'); editorEl.style.position = 'absolute'; editorEl.style.left = `${rect.left}px`; editorEl.style.top = `${rect.top}px`; editorEl.style.width = `${rect.width}px`; editorEl.style.height = `${rect.height}px`; editorEl.style.zIndex = 2000; const editorCanvas = document.createElement('canvas'); editorCanvas.width = rect.width * window.devicePixelRatio; editorCanvas.height = rect.height * window.devicePixelRatio; editorCanvas.style.width = `${rect.width}px`; editorCanvas.style.height = `${rect.height}px`; editorEl.appendChild(editorCanvas); const editorCtx = editorCanvas.getContext("2d"); editorCtx.drawImage(el.querySelector('.file-preview img'), 0, 0, editorCanvas.width, editorCanvas.height); editorCtx.strokeStyle = "#df4b26"; editorCtx.lineJoin = "round"; editorCtx.lineWidth = 3 * window.devicePixelRatio; let penDown = false; let penXY = null; editorCanvas.addEventListener('mousedown', (event) => { penDown = true; penXY = { x: event.offsetX, y: event.offsetY, } }); editorCanvas.addEventListener('mousemove', (event) => { if (penDown) { const nextPenXY = { x: event.offsetX, y: event.offsetY, } editorCtx.beginPath(); editorCtx.moveTo(penXY.x * window.devicePixelRatio, penXY.y * window.devicePixelRatio); editorCtx.lineTo(nextPenXY.x * window.devicePixelRatio, nextPenXY.y * window.devicePixelRatio); editorCtx.closePath(); editorCtx.stroke(); penXY = nextPenXY; } }); editorCanvas.addEventListener('mouseup', () => { penDown = false; penXY = null; }); const backgroundEl = document.createElement('div'); backgroundEl.style.background = 'rgba(0,0,0,0.4)'; backgroundEl.style.position = 'absolute'; backgroundEl.style.top = '0px'; backgroundEl.style.left = '0px'; backgroundEl.style.right = '0px'; backgroundEl.style.bottom = '0px'; backgroundEl.style.zIndex = 1999; backgroundEl.addEventListener('click', () => { editorCanvas.toBlob((blob) => { const reader = new FileReader(); reader.addEventListener('loadend', () => { const {draft, session, uploadId} = this.props; const buffer = new Buffer(new Uint8Array(reader.result)); const upload = draft.uploads.find(u => u.id === uploadId ); const nextTargetPath = path.join(path.dirname(upload.targetPath), `edited-${Date.now()}.png`); fs.writeFile(nextTargetPath, buffer, (err) => { if (err) { NylasEnv.showErrorDialog(err.toString()) return; } const img = el.querySelector('.file-preview img'); img.style.width = `${rect.width}px`; img.style.height = `${rect.height}px`; img.src = `${img.src}?${Date.now()}`; fs.unlink(upload.targetPath); const nextUploads = [].concat(draft.uploads); nextUploads.forEach((u) => { if (u.targetPath === upload.targetPath) { u.targetPath = nextTargetPath; } }); session.changes.add({uploads: nextUploads}); }); }); reader.readAsArrayBuffer(blob); }); document.body.removeChild(editorEl); document.body.removeChild(backgroundEl); }); document.body.appendChild(backgroundEl); document.body.appendChild(editorEl); } render() { const {draft, uploadId, isPreview} = this.props; const upload = draft.uploads.find(u => uploadId === u.id); if (!upload) { return ( ); } if (isPreview) { return ( {upload.name} ); } return (
Actions.removeAttachment(upload)} />
) } } ================================================ FILE: packages/client-app/internal_packages/composer/lib/main.jsx ================================================ /* eslint react/sort-comp: 0 */ import _ from 'underscore'; import React from 'react'; import { Message, Actions, DraftStore, WorkspaceStore, ComponentRegistry, ExtensionRegistry, InflatesDraftClientId, CustomContenteditableComponents, } from 'nylas-exports'; import {OverlaidComposerExtension} from 'nylas-component-kit' import ComposeButton from './compose-button'; import ComposerView from './composer-view'; import ImageUploadComposerExtension from './image-upload-composer-extension'; import InlineImageUploadContainer from "./inline-image-upload-container"; const ComposerViewForDraftClientId = InflatesDraftClientId(ComposerView); class ComposerWithWindowProps extends React.Component { static displayName = 'ComposerWithWindowProps'; static containerRequired = false; constructor(props) { super(props); // We'll now always have windowProps by the time we construct this. const windowProps = NylasEnv.getWindowProps(); const {draftJSON, draftClientId} = windowProps; if (!draftJSON) { throw new Error("Initialize popout composer windows with valid draftJSON") } const draft = new Message().fromJSON(draftJSON); DraftStore._createSession(draftClientId, draft); this.state = windowProps } componentWillUnmount() { if (this._usub) { this._usub() } } componentDidUpdate() { this.refs.composer.focus() } _onDraftReady = () => { this.refs.composer.focus().then(() => { NylasEnv.displayWindow(); this._recordComposerOpenTime() if (this.state.errorMessage) { this._showInitialErrorDialog(this.state.errorMessage, this.state.errorDetail); } // This will start loading the rest of the composer's plugins. This // may take a while (hundreds of ms) depending on how many plugins // you have installed. For some reason it takes two frames to // reliably get the basic composer (Send button, etc) painted // properly. window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { NylasEnv.getCurrentWindow().updateLoadSettings({ windowType: "composer", }) }) }) }); } _recordComposerOpenTime() { const {timerId} = NylasEnv.getWindowProps() const timerKey = `open-composer-window-${timerId}` if (NylasEnv.timer.isPending(timerKey)) { const actionTimeMs = NylasEnv.timer.stop(timerKey); if (actionTimeMs && actionTimeMs <= 4000) { // TODO do we still need to record this legacy event? Actions.recordUserEvent("Composer Popout Timed", {timeInMs: actionTimeMs}) } Actions.recordPerfMetric({ action: 'open-composer-window', actionTimeMs, maxValue: 4000, sample: 0.9, }) } } render() { return ( ); } _showInitialErrorDialog(msg, detail) { // We delay so the view has time to update the restored draft. If we // don't delay the modal may come up in a state where the draft looks // like it hasn't been restored or has been lost. _.delay(() => { NylasEnv.showErrorDialog({title: 'Error', message: msg}, {detail: detail}) }, 100); } } export function activate() { if (NylasEnv.isMainWindow()) { ComponentRegistry.register(ComposerViewForDraftClientId, { role: 'Composer', }); ComponentRegistry.register(ComposeButton, { location: WorkspaceStore.Location.RootSidebar.Toolbar, }); } else if (NylasEnv.isThreadWindow()) { ComponentRegistry.register(ComposerViewForDraftClientId, { role: 'Composer', }); } else { NylasEnv.getCurrentWindow().setMinimumSize(480, 250); ComponentRegistry.register(ComposerWithWindowProps, { location: WorkspaceStore.Location.Center, }); } ExtensionRegistry.Composer.register(OverlaidComposerExtension, {priority: 1}) ExtensionRegistry.Composer.register(ImageUploadComposerExtension); CustomContenteditableComponents.register("InlineImageUploadContainer", InlineImageUploadContainer); } export function deactivate() { if (NylasEnv.isMainWindow()) { ComponentRegistry.unregister(ComposerViewForDraftClientId); ComponentRegistry.unregister(ComposeButton); } else { ComponentRegistry.unregister(ComposerWithWindowProps); } ExtensionRegistry.Composer.unregister(OverlaidComposerExtension) ExtensionRegistry.Composer.unregister(ImageUploadComposerExtension); CustomContenteditableComponents.unregister("InlineImageUploadContainer"); } export function serialize() { return this.state; } ================================================ FILE: packages/client-app/internal_packages/composer/lib/send-action-button.jsx ================================================ import React from 'react' import {Actions, SendActionsStore} from 'nylas-exports' import {Menu, RetinaImg, ButtonDropdown, ListensToFluxStore} from 'nylas-component-kit' class SendActionButton extends React.Component { static displayName = "SendActionButton"; static containerRequired = false static propTypes = { draft: React.PropTypes.object, isValidDraft: React.PropTypes.func, sendActions: React.PropTypes.array, orderedSendActions: React.PropTypes.object, }; primarySend() { this._onPrimaryClick(); } _onPrimaryClick = () => { const {orderedSendActions} = this.props const {preferred} = orderedSendActions this._onSendWithAction(preferred); } _onSendWithAction = (sendAction) => { const {isValidDraft, draft} = this.props if (isValidDraft()) { Actions.sendDraft(draft.clientId, sendAction.configKey) } } _renderSendActionItem = ({iconUrl}) => { let plusHTML = ""; let additionalImg = false; if (iconUrl) { plusHTML =  + ; additionalImg = ; } return ( Send{plusHTML}{additionalImg} ); } _renderSingleButton() { const {sendActions} = this.props return ( ); } _renderButtonDropdown() { const {orderedSendActions} = this.props const {preferred, rest} = orderedSendActions const menu = ( actionConfig.configKey} itemContent={this._renderSendActionItem} onSelect={this._onSendWithAction} /> ); return ( ); } render() { const {sendActions} = this.props if (sendActions.length === 1) { return this._renderSingleButton(); } return this._renderButtonDropdown(); } } const EnhancedSendActionButton = ListensToFluxStore(SendActionButton, { stores: [SendActionsStore], getStateFromStores(props) { const {draft} = props return { sendActions: SendActionsStore.availableSendActionsForDraft(draft), orderedSendActions: SendActionsStore.orderedSendActionsForDraft(draft), } }, }) // TODO this is a hack so that the send button can still expose // the `primarySend` method required by the ComposerView. Ideally, this // decorator mechanism should expose whatever instance methods are exposed // by the component its wrapping. // However, I think the better fix will happen when mail merge lives in its // own window and doesn't need to override the Composer's send button, which // is already a bit of a hack. Object.assign(EnhancedSendActionButton.prototype, { primarySend() { if (this.refs.composed) { this.refs.composed.primarySend() } }, }) EnhancedSendActionButton.UndecoratedSendActionButton = SendActionButton export default EnhancedSendActionButton ================================================ FILE: packages/client-app/internal_packages/composer/lib/subject-text-field.jsx ================================================ import React, {Component, PropTypes} from 'react' import {findDOMNode} from 'react-dom' export default class SubjectTextField extends Component { static displayName = 'SubjectTextField' static containerRequired = false static propTypes = { value: PropTypes.string, onSubjectChange: PropTypes.func, } onInputChange = ({target: {value}}) => { this.props.onSubjectChange(value) } focus() { findDOMNode(this.refs.input).focus() } render() { const {value} = this.props return (
); } } ================================================ FILE: packages/client-app/internal_packages/composer/package.json ================================================ { "name": "composer", "version": "0.1.0", "main": "./lib/main", "description": "Nylas Composer Component", "license": "GPL-3.0", "private": true, "scripts": { }, "engines": { "nylas": "*" }, "windowTypes": { "default": true, "composer": true, "composer-preload": true, "thread-popout": true } } ================================================ FILE: packages/client-app/internal_packages/composer/spec/collapsed-participants-spec.cjsx ================================================ _ = require "underscore" React = require "react" ReactDOM = require 'react-dom' ReactTestUtils = require 'react-addons-test-utils' Fields = require('../lib/fields').default CollapsedParticipants = require('../lib/collapsed-participants').default {Contact} = require 'nylas-exports' describe "CollapsedParticipants", -> makeField = (props={}) -> @fields = ReactTestUtils.renderIntoDocument( ) numStr = -> ReactDOM.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithClass(@fields, "num-remaining")).innerHTML it "doesn't render num remaining when nothing remains", -> makeField.call(@) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@fields, "num-remaining") expect(els.length).toBe 0 it "renders num remaining when remaining with no bcc", -> makeField.call(@) spyOn(@fields, "_setNumHiddenParticipants") @fields.setState numRemaining: 10, numBccRemaining: 0 str = numStr.call(@) expect(str).toBe "10 more" it "renders num remaining when only bcc", -> makeField.call(@) spyOn(@fields, "_setNumHiddenParticipants") @fields.setState numRemaining: 0, numBccRemaining: 5 str = numStr.call(@) expect(str).toBe "5 Bcc" it "renders num remaining when both remaining andj bcc", -> makeField.call(@) spyOn(@fields, "_setNumHiddenParticipants") @fields.setState numRemaining: 10, numBccRemaining: 5 str = numStr.call(@) expect(str).toBe "15 more (5 Bcc)" ================================================ FILE: packages/client-app/internal_packages/composer/spec/composer-header-actions-spec.cjsx ================================================ React = require 'react' ReactDOM = require 'react-dom' ComposerHeaderActions = require('../lib/composer-header-actions').default Fields = require('../lib/fields').default ReactTestUtils = require('react-addons-test-utils') {Actions} = require 'nylas-exports' describe "ComposerHeaderActions", -> makeField = (props = {}) -> @onShowAndFocusField = jasmine.createSpy("onShowAndFocusField") props.onShowAndFocusField = @onShowAndFocusField props.enabledFields ?= [] props.draftClientId = 'a' @component = ReactTestUtils.renderIntoDocument( ) it "renders the 'show' buttons for 'cc', 'bcc' when participantsFocused", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) showCc = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-cc") showBcc = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-bcc") showSubject = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-subject") expect(showCc).toBeDefined() expect(showBcc).toBeDefined() it "does not render the 'show' buttons for 'cc', 'bcc' when participantsFocused is false", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: false}) showCc = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-cc") showBcc = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-bcc") showSubject = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-subject") expect(showCc.length).toBe 0 expect(showBcc.length).toBe 0 it "hides show cc if it's enabled", -> makeField.call(@, {enabledFields: [Fields.To, Fields.Cc], participantsFocused: true}) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-cc") expect(els.length).toBe 0 it "hides show bcc if it's enabled", -> makeField.call(@, {enabledFields: [Fields.To, Fields.Bcc], participantsFocused: true}) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-bcc") expect(els.length).toBe 0 it "hides show subject if it's enabled", -> makeField.call(@, {enabledFields: [Fields.To, Fields.Subject], participantsFocused: true}) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-subject") expect(els.length).toBe 0 it "renders 'popout composer' in the inline mode", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-popout") expect(els.length).toBe 1 it "doesn't render 'popout composer' if in a composer window", -> spyOn(NylasEnv, 'isComposerWindow').andReturn(true) makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) els = ReactTestUtils.scryRenderedDOMComponentsWithClass(@component, "show-popout") expect(els.length).toBe 0 it "pops out the composer when clicked", -> spyOn(Actions, "composePopoutDraft") makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-popout") ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(el)) expect(Actions.composePopoutDraft).toHaveBeenCalled() it "shows and focuses cc when clicked", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-cc") ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(el)) expect(@onShowAndFocusField).toHaveBeenCalledWith Fields.Cc it "shows and focuses bcc when clicked", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: true}) el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-bcc") ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(el)) expect(@onShowAndFocusField).toHaveBeenCalledWith Fields.Bcc it "shows subject when clicked", -> makeField.call(@, {enabledFields: [Fields.To], participantsFocused: false}) el = ReactTestUtils.findRenderedDOMComponentWithClass(@component, "show-subject") ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(el)) expect(@onShowAndFocusField).toHaveBeenCalledWith Fields.Subject ================================================ FILE: packages/client-app/internal_packages/composer/spec/composer-header-spec.jsx ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-addons-test-utils'; import {Contact, Message} from 'nylas-exports'; import ComposerHeader from '../lib/composer-header'; import Fields from '../lib/fields'; describe('ComposerHeader', function composerHeader() { beforeEach(() => { this.createWithDraft = (draft) => { const session = { changes: { add: jasmine.createSpy('changes.add'), }, }; this.component = ReactTestUtils.renderIntoDocument( ) }; advanceClock() }); describe("showAndFocusField", () => { beforeEach(() => { const draft = new Message({ draft: true, accountId: TEST_ACCOUNT_ID, }); this.createWithDraft(draft); }); it("should ensure the field is in enabledFields", () => { expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField', 'textFieldSubject']) this.component.showAndFocusField(Fields.Bcc); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField', 'textFieldSubject', 'textFieldBcc']) }); it("should ensure participantsFocused is true if necessary", () => { expect(this.component.state.participantsFocused).toEqual(false); this.component.showAndFocusField(Fields.Subject); expect(this.component.state.participantsFocused).toEqual(false); this.component.showAndFocusField(Fields.Bcc); expect(this.component.state.participantsFocused).toEqual(true); }); it("should wait for the field to become available and then focus it", () => { const $el = ReactDOM.findDOMNode(this.component); expect($el.querySelector('.bcc-field')).toBe(null); this.component.showAndFocusField(Fields.Bcc); advanceClock(); expect($el.querySelector('.bcc-field')).not.toBe(null); }); }); describe("hideField", () => { beforeEach(() => { const draft = new Message({draft: true, accountId: TEST_ACCOUNT_ID}); this.createWithDraft(draft); }); it("should remove the field from enabledFields", () => { const $el = ReactDOM.findDOMNode(this.component); this.component.showAndFocusField(Fields.Bcc); advanceClock(); expect($el.querySelector('.bcc-field')).not.toBe(null); this.component.hideField(Fields.Bcc); advanceClock(); expect($el.querySelector('.bcc-field')).toBe(null); }); }); describe("initial state", () => { it("should enable any fields that are populated", () => { let draft = null; draft = new Message({draft: true, accountId: TEST_ACCOUNT_ID}); this.createWithDraft(draft); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField', 'textFieldSubject']) draft = new Message({ draft: true, cc: [new Contact({id: 'a', email: 'a'})], bcc: [new Contact({id: 'b', email: 'b'})], accountId: TEST_ACCOUNT_ID, }); this.createWithDraft(draft); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'textFieldCc', 'textFieldBcc', 'fromField', 'textFieldSubject']) }); describe("subject", () => { it("should be enabled if it is empty", () => { const draft = new Message({draft: true, subject: '', accountId: TEST_ACCOUNT_ID}); this.createWithDraft(draft); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField', 'textFieldSubject']) }); it("should be enabled if the message is a forward", () => { const draft = new Message({draft: true, subject: 'Fwd: 1234', accountId: TEST_ACCOUNT_ID}); this.createWithDraft(draft); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField', 'textFieldSubject']) }); it("should be hidden if the message is a reply", () => { const draft = new Message({draft: true, subject: 'Re: 1234', replyToMessageId: '123', accountId: TEST_ACCOUNT_ID}); this.createWithDraft(draft); expect(this.component.state.enabledFields).toEqual(['textFieldTo', 'fromField']) }); }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer/spec/composer-view-spec.cjsx ================================================ _ = require "underscore" React = require "react" ReactDOM = require 'react-dom' ReactTestUtils = require('react-addons-test-utils') {Actions, Utils, File, Contact, Message, Account, DraftStore, DatabaseStore, NylasTestUtils, AccountStore, FileUploadStore, ContactStore, FocusedContentStore, ComponentRegistry} = require "nylas-exports" {InjectedComponent, ParticipantsTextField} = require 'nylas-component-kit' DraftEditingSession = require '../../../src/flux/stores/draft-editing-session' ComposerEditor = require('../lib/composer-editor').default Fields = require('../lib/fields').default u1 = new Contact(name: "Christine Spang", email: "spang@nylas.com") u2 = new Contact(name: "Michael Grinich", email: "mg@nylas.com") u3 = new Contact(name: "Evan Morikawa", email: "evan@nylas.com") u4 = new Contact(name: "Zoë Leiper", email: "zip@nylas.com") u5 = new Contact(name: "Ben Gotow", email: "ben@nylas.com") f1 = new File(id: 'file_1_id', filename: 'a.png', contentType: 'image/png', size: 10, object: "file") f2 = new File(id: 'file_2_id', filename: 'b.pdf', contentType: '', size: 999999, object: "file") users = [u1, u2, u3, u4, u5] ComposerView = require("../lib/composer-view").default # This will setup the mocks necessary to make the composer element (once # mounted) think it's attached to the given draft. This mocks out the # proxy system used by the composer. DRAFT_CLIENT_ID = "local-123" useDraft = (draftAttributes={}) -> @draft = new Message _.extend({draft: true, body: ""}, draftAttributes) @draft.clientId = DRAFT_CLIENT_ID @session = new DraftEditingSession(DRAFT_CLIENT_ID, @draft) # spyOn().andCallFake wasn't working properly on ensureCorrectAccount for some reason @session.ensureCorrectAccount = => Promise.resolve(@session) DraftStore._draftSessions[DRAFT_CLIENT_ID] = @session @session._draftPromise useFullDraft = -> useDraft.call @, from: [AccountStore.accounts()[0].me()] to: [u2] cc: [u3, u4] bcc: [u5] files: [f1, f2] subject: "Test Message 1" body: "Hello World
This is a test" replyToMessageId: null makeComposer = (props={}) -> @composer = NylasTestUtils.renderIntoDocument( ) advanceClock() describe "ComposerView", -> beforeEach -> ComposerEditor.containerRequired = false ComponentRegistry.register(ComposerEditor, role: "Composer:Editor") spyOn(Actions, 'queueTask') spyOn(Actions, 'queueTasks') spyOn(DraftStore, "isSendingDraft").andCallThrough() spyOn(DraftEditingSession.prototype, 'changeSetCommit').andCallFake (draft) => @draft = draft spyOn(ContactStore, "searchContacts").andCallFake (email) => return _.filter(users, (u) u.email.toLowerCase() is email.toLowerCase()) spyOn(Contact.prototype, "isValid").andCallFake (contact) -> return @email.indexOf('@') > 0 afterEach -> ComposerEditor.containerRequired = undefined ComponentRegistry.unregister(ComposerEditor) DraftStore._cleanupAllSessions() NylasTestUtils.removeFromDocument(@composer) describe "when sending a new message", -> it 'makes a request with the message contents', -> sessionSetupComplete = false useDraft.call(@).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) editableNode = ReactDOM.findDOMNode(@composer).querySelector('[contenteditable]') spyOn(@session.changes, "add") editableNode.innerHTML = "Hello world" @composer.refs[Fields.Body]._onDOMMutated(["mutated"]) expect(@session.changes.add).toHaveBeenCalled() expect(@session.changes.add.calls.length).toBe 1 body = @session.changes.add.calls[0].args[0].body expect(body).toBe "Hello world" ) describe "when sending a reply-to message", -> beforeEach -> sessionSetupComplete = false useDraft.call(@, from: [u1] to: [u2] subject: "Test Reply Message 1" body: "" replyToMessageId: "1") .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) @editableNode = ReactDOM.findDOMNode(@composer).querySelector('[contenteditable]') spyOn(@session.changes, "add") ) it 'begins with empty body', -> expect(@editableNode.innerHTML).toBe "" describe "when sending a forwarded message", -> beforeEach -> @fwdBody = """

---------- Forwarded message ---------

From: Evan Morikawa <evan@evanmorikawa.com>
Subject: Test Forward Message 1
Date: Sep 3 2015, at 12:14 pm
To: Evan Morikawa <evan@nylas.com>

This is a test!
""" sessionSetupComplete = false useDraft.call(@, from: [u1] to: [u2] subject: "Fwd: Test Forward Message 1" body: @fwdBody) .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) @editableNode = ReactDOM.findDOMNode(@composer).querySelector('[contenteditable]') spyOn(@session.changes, "add") ) it 'begins with the forwarded message expanded', -> expect(@editableNode.innerHTML).toBe @fwdBody it 'saves the full new body, plus forwarded text', -> @editableNode.innerHTML = "Hello world#{@fwdBody}" @composer.refs[Fields.Body]._onDOMMutated(["mutated"]) expect(@session.changes.add).toHaveBeenCalled() expect(@session.changes.add.calls.length).toBe 1 body = @session.changes.add.calls[0].args[0].body expect(body).toBe """Hello world#{@fwdBody}""" describe "When sending a message", -> beforeEach -> spyOn(NylasEnv, "isMainWindow").andReturn true {remote} = require('electron') @dialog = remote.dialog spyOn(remote, "getCurrentWindow") spyOn(@dialog, "showMessageBox") spyOn(Actions, "sendDraft").andCallThrough() it "shows an error if there are no recipients", -> sessionSetupComplete = false useDraft.call(@, subject: "no recipients").then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe false expect(@dialog.showMessageBox).toHaveBeenCalled() dialogArgs = @dialog.showMessageBox.mostRecentCall.args[1] expect(dialogArgs.detail).toEqual("You need to provide one or more recipients before sending the message.") expect(dialogArgs.buttons).toEqual ['Edit Message', 'Cancel'] ) it "shows an error if a recipient is invalid", -> sessionSetupComplete = false useDraft.call(@, subject: 'hello world!' to: [new Contact(email: 'lol', name: 'lol')]) .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe false expect(@dialog.showMessageBox).toHaveBeenCalled() dialogArgs = @dialog.showMessageBox.mostRecentCall.args[1] expect(dialogArgs.detail).toEqual("lol is not a valid email address - please remove or edit it before sending.") expect(dialogArgs.buttons).toEqual ['Edit Message', 'Cancel'] ) describe "empty body warning", -> it "warns if the body of the email is still the pristine body", -> pristineBody = "

" sessionSetupComplete = false useDraft.call(@, to: [u1] subject: "Hello World" body: pristineBody) .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) spyOn(@session, 'draftPristineBody').andCallFake -> pristineBody status = @composer._isValidDraft() expect(status).toBe false expect(@dialog.showMessageBox).toHaveBeenCalled() dialogArgs = @dialog.showMessageBox.mostRecentCall.args[1] expect(dialogArgs.buttons).toEqual ['Send Anyway', 'Cancel'] ) it "does not warn if the body of the email is all quoted text, but the email is a forward", -> sessionSetupComplete = false useDraft.call(@, to: [u1] subject: "Fwd: Hello World" body: "

This is my quoted text!
") .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe true ) it "does not warn if the user has attached a file", -> sessionSetupComplete = false useDraft.call(@, to: [u1] subject: "Hello World" body: "" files: [f1]) .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe true expect(@dialog.showMessageBox).not.toHaveBeenCalled() ) it "shows a warning if there's no subject", -> sessionSetupComplete = false useDraft.call(@, to: [u1], subject: "").then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe false expect(@dialog.showMessageBox).toHaveBeenCalled() dialogArgs = @dialog.showMessageBox.mostRecentCall.args[1] expect(dialogArgs.buttons).toEqual ['Send Anyway', 'Cancel'] ) it "doesn't show a warning if requirements are satisfied", -> sessionSetupComplete = false useFullDraft.apply(@).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe true expect(@dialog.showMessageBox).not.toHaveBeenCalled() ) describe "Checking for attachments", -> warn = (body) -> sessionSetupComplete = false useDraft.call(@, subject: "Subject", to: [u1], body: body).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe false expect(@dialog.showMessageBox).toHaveBeenCalled() dialogArgs = @dialog.showMessageBox.mostRecentCall.args[1] expect(dialogArgs.buttons).toEqual ['Send Anyway', 'Cancel'] ) noWarn = (body) -> sessionSetupComplete = false useDraft.call(@, subject: "Subject", to: [u1], body: body).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe true expect(@dialog.showMessageBox).not.toHaveBeenCalled() ) it "warns", -> warn.call(@, "Check out the attached file") it "warns", -> warn.call(@, "I've added an attachment") it "warns", -> warn.call(@, "I'm going to attach the file") it "warns", -> warn.call(@, "Hey attach me
sup
") it "doesn't warn", -> noWarn.call(@, "sup yo") it "doesn't warn", -> noWarn.call(@, "Look at the file") it "doesn't warn", -> noWarn.call(@, "Hey there
attach
") it "doesn't show a warning if you've attached a file", -> sessionSetupComplete = false useDraft.call(@, subject: "Subject" to: [u1] body: "Check out attached file" files: [f1]) .then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft() expect(status).toBe true expect(@dialog.showMessageBox).not.toHaveBeenCalled() ) it "bypasses the warning if force bit is set", -> sessionSetupComplete = false useDraft.call(@, to: [u1], subject: "").then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) status = @composer._isValidDraft(force: true) expect(status).toBe true expect(@dialog.showMessageBox).not.toHaveBeenCalled() ) it "sends when you click the send button", -> sessionSetupComplete = false useFullDraft.apply(@).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) sendBtn = @composer.refs.sendActionButton sendBtn.primarySend() expect(Actions.sendDraft).toHaveBeenCalledWith(DRAFT_CLIENT_ID, 'send') expect(Actions.sendDraft.calls.length).toBe 1 # Delete the draft from _draftsSending so we can send it in other tests delete DraftStore._draftsSending[DRAFT_CLIENT_ID] ) it "doesn't send twice if you double click", => sessionSetupComplete = false useFullDraft.apply(@).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) sendBtn = @composer.refs.sendActionButton sendBtn.primarySend() sendBtn.primarySend() expect(Actions.sendDraft).toHaveBeenCalledWith(DRAFT_CLIENT_ID, 'send') expect(Actions.sendDraft.calls.length).toBe 1 # Delete the draft from _draftsSending so we can send it in other tests delete DraftStore._draftsSending[DRAFT_CLIENT_ID] ) describe "when sending a message with keyboard inputs", -> beforeEach -> sessionSetupComplete = false useFullDraft.apply(@).then => makeComposer.call(@) @$composer = @composer.refs.composerWrap sessionSetupComplete = true waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) afterEach -> # Delete the draft from _draftsSending so we can send it in other tests delete DraftStore._draftsSending[DRAFT_CLIENT_ID] it "sends the draft on cmd-enter", -> ReactDOM.findDOMNode(@$composer).dispatchEvent(new CustomEvent('composer:send-message')) expect(Actions.sendDraft).toHaveBeenCalledWith(DRAFT_CLIENT_ID, 'send') expect(Actions.sendDraft.calls.length).toBe 1 it "doesn't let you send twice", -> ReactDOM.findDOMNode(@$composer).dispatchEvent(new CustomEvent('composer:send-message')) expect(Actions.sendDraft).toHaveBeenCalledWith(DRAFT_CLIENT_ID, 'send') expect(Actions.sendDraft.calls.length).toBe 1 ReactDOM.findDOMNode(@$composer).dispatchEvent(new CustomEvent('composer:send-message')) expect(Actions.sendDraft).toHaveBeenCalledWith(DRAFT_CLIENT_ID, 'send') expect(Actions.sendDraft.calls.length).toBe 1 describe "drag and drop", -> beforeEach -> sessionSetupComplete = false useDraft.call(@, to: [u1] subject: "Hello World" body: "" files: [f1]) .then( => makeComposer.call(@) sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) describe "_shouldAcceptDrop", -> it "should return true if the event is carrying native files", -> event = dataTransfer: files:[{'pretend':'imafile'}] types:[] expect(@composer._shouldAcceptDrop(event)).toBe(true) it "should return true if the event is carrying a non-native file URL", -> event = dataTransfer: files:[] types:['text/uri-list'] spyOn(@composer, '_nonNativeFilePathForDrop').andReturn("file://one-file") expect(@composer._shouldAcceptDrop(event)).toBe(true) expect(@draft.files.length).toBe(1) it "should return false otherwise", -> event = dataTransfer: files:[] types:['text/plain'] expect(@composer._shouldAcceptDrop(event)).toBe(false) describe "_nonNativeFilePathForDrop", -> it "should return a path in the text/nylas-file-url data", -> event = dataTransfer: types: ['text/nylas-file-url'] getData: -> "image/png:test.png:file:///Users/bengotow/Desktop/test.png" expect(@composer._nonNativeFilePathForDrop(event)).toBe("/Users/bengotow/Desktop/test.png") it "should return a path in the text/uri-list data", -> event = dataTransfer: types: ['text/uri-list'] getData: -> "file:///Users/bengotow/Desktop/test.png" expect(@composer._nonNativeFilePathForDrop(event)).toBe("/Users/bengotow/Desktop/test.png") it "should return null otherwise", -> event = dataTransfer: types: ['text/plain'] getData: -> "Hello world" expect(@composer._nonNativeFilePathForDrop(event)).toBe(null) it "should urldecode the contents of the text/uri-list field", -> event = dataTransfer: types: ['text/uri-list'] getData: -> "file:///Users/bengotow/Desktop/Screen%20shot.png" expect(@composer._nonNativeFilePathForDrop(event)).toBe("/Users/bengotow/Desktop/Screen shot.png") it "should return null if text/uri-list contains a non-file path", -> event = dataTransfer: types: ['text/uri-list'] getData: -> "http://apple.com" expect(@composer._nonNativeFilePathForDrop(event)).toBe(null) it "should return null if text/nylas-file-url contains a non-file path", -> event = dataTransfer: types: ['text/nylas-file-url'] getData: -> "application/json:filename.json:undefined" expect(@composer._nonNativeFilePathForDrop(event)).toBe(null) describe "A draft with files (attachments) and uploads", -> beforeEach -> @file1 = new File id: "f_1" filename: "f1.pdf" size: 1230 @file2 = new File id: "f_2" filename: "f2.jpg" size: 4560 @file3 = new File id: "f_3" filename: "f3.png" size: 7890 spyOn(Actions, "fetchFile") sessionSetupComplete = false useDraft.call(@, files: [@file1, @file2]).then( => makeComposer.call(@) sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) it 'starts fetching attached files', -> waitsFor -> Actions.fetchFile.callCount == 1 runs -> expect(Actions.fetchFile).toHaveBeenCalled() expect(Actions.fetchFile.calls.length).toBe(1) expect(Actions.fetchFile.calls[0].args[0]).toBe @file2 it 'injects a MessageAttachments component for any present attachments', -> els = ReactTestUtils.scryRenderedComponentsWithTypeAndProps(@composer, InjectedComponent, matching: {role: "MessageAttachments"}) expect(els.length).toBe 1 el = els[0] expect(el.props.exposedProps.files).toEqual(@draft.files) describe "when a file is received (via drag and drop or paste)", -> beforeEach -> sessionSetupComplete = false useDraft.call(@).then( => sessionSetupComplete = true ) waitsFor(( => sessionSetupComplete), "The session's draft needs to be set", 500) runs( => makeComposer.call(@) @upload = {targetPath: 'a/f.txt', size: 1000, name: 'f.txt', id: 'f'} spyOn(Actions, 'addAttachment').andCallFake ({filePath, messageClientId, onUploadCreated}) => @draft.uploads.push(@upload) onUploadCreated(@upload) spyOn(Actions, 'insertAttachmentIntoDraft') ) it "should call addAttachment with the path and clientId", -> @composer._onFileReceived('../../f.txt') expect(Actions.addAttachment.callCount).toBe(1) expect(Object.keys(Actions.addAttachment.calls[0].args[0])).toEqual([ 'filePath', 'messageClientId', 'onUploadCreated', ]) it "should call insertAttachmentIntoDraft if the upload looks like an image", -> @upload = {targetPath: 'a/f.txt', size: 1000, name: 'f.txt', id: 'f'} @composer._onFileReceived('../../f.txt') advanceClock() expect(Actions.insertAttachmentIntoDraft).not.toHaveBeenCalled() expect(@upload.inline).not.toEqual(true) @upload = {targetPath: 'a/f.png', size: 1000, name: 'f.png', id: 'g'} expect(Utils.shouldDisplayAsImage(@upload)).toBe(true) # sanity check @composer._onFileReceived('../../f.png') advanceClock() expect(Actions.insertAttachmentIntoDraft).toHaveBeenCalled() expect(@upload.inline).toEqual(true) ================================================ FILE: packages/client-app/internal_packages/composer/spec/quoted-text-spec.cjsx ================================================ # This tests just quoted text within a contenteditable. # # For a test of the basic component itself see # contenteditable-component-spec.cjsx # _ = require "underscore" React = require "react" ReactDOM = require 'react-dom' ReactTestUtils = require('react-addons-test-utils') Fields = require('../lib/fields').default Composer = require("../lib/composer-view").default ComposerEditor = require('../lib/composer-editor').default {Message, DraftStore, ComponentRegistry} = require 'nylas-exports' describe "Composer Quoted Text", -> beforeEach -> ComponentRegistry.register(ComposerEditor, role: "Composer:Editor") @onChange = jasmine.createSpy('onChange') @htmlNoQuote = 'Test HTML
' @htmlWithQuote = 'Test HTML

QUOTE
' @draft = new Message(draft: true, clientId: "client-123") @session = trigger: -> changes: add: jasmine.createSpy('changes.add') draft: => @draft afterEach -> DraftStore._cleanupAllSessions() ComposerEditor.containerRequired = undefined ComponentRegistry.unregister(ComposerEditor) # Must be called with the test's scope setHTML = (newHTML) -> @$contentEditable.innerHTML = newHTML @contentEditable._onDOMMutated(["mutated"]) describe "when the message is a reply", -> beforeEach -> @draft.body = @htmlNoQuote @composer = ReactTestUtils.renderIntoDocument( ) @composer.setState showQuotedText: false showQuotedTextControl: true @contentEditable = @composer.refs[Fields.Body] @$contentEditable = ReactDOM.findDOMNode(@contentEditable).querySelector('[contenteditable]') @$composerBodyWrap = ReactDOM.findDOMNode(@composer.refs.composerBodyWrap) it 'should render the quoted-text-control toggle', -> toggles = ReactTestUtils.scryRenderedDOMComponentsWithClass(@composer, 'quoted-text-control') expect(toggles.length).toBe 1 describe 'when the quoted text has been expanded', -> beforeEach -> @draft.body = @htmlWithQuote @composer = ReactTestUtils.renderIntoDocument( ) @composer.setState showQuotedText: true showQuotedTextControl: false @contentEditable = @composer.refs[Fields.Body] @$contentEditable = ReactDOM.findDOMNode(@contentEditable).querySelector('[contenteditable]') @$composerBodyWrap = ReactDOM.findDOMNode(@composer.refs.composerBodyWrap) it "should call add changes with the entire HTML string", -> textToAdd = "MORE TEXT!" expect(@$contentEditable.innerHTML).toBe @htmlWithQuote setHTML.call(@, textToAdd + @htmlWithQuote) ev = @session.changes.add.mostRecentCall.args[0].body expect(ev).toEqual(textToAdd + @htmlWithQuote) it "should allow the quoted text to be changed", -> newText = 'Test NEW 1 HTML
QUOTE CHANGED!!!
' expect(@$contentEditable.innerHTML).toBe @htmlWithQuote setHTML.call(@, newText) ev = @session.changes.add.mostRecentCall.args[0].body expect(ev).toEqual(newText) describe 'quoted text control toggle button', -> it 'should not be rendered', -> toggles = ReactTestUtils.scryRenderedDOMComponentsWithClass(@composer, 'quoted-text-control') expect(toggles.length).toBe(0) ================================================ FILE: packages/client-app/internal_packages/composer/spec/send-action-button-spec.jsx ================================================ import React from 'react'; import {mount} from 'enzyme'; import {ButtonDropdown, RetinaImg} from 'nylas-component-kit'; import {Actions, Message, SendActionsStore} from 'nylas-exports'; import SendActionButton from '../lib/send-action-button'; const {UndecoratedSendActionButton} = SendActionButton; const {DefaultSendAction} = SendActionsStore const GoodSendAction = { title: "Good Send Action", configKey: 'good-send-action', isAvailableForDraft: () => true, performSendAction: () => {}, } const SecondSendAction = { title: "Second Send Action", configKey: 'second-send-action', isAvailableForDraft: () => true, performSendAction: () => {}, } const NoIconUrl = { title: "No Icon", configKey: 'no-icon', iconUrl: null, isAvailableForDraft: () => true, performSendAction() {}, } describe('SendActionButton', function describeBlock() { beforeEach(() => { spyOn(NylasEnv, 'reportError') spyOn(Actions, 'sendDraft') this.isValidDraft = jasmine.createSpy('isValidDraft') this.clientId = "client-23" this.draft = new Message({clientId: this.clientId, draft: true}) }) const render = (draft, {isValid = true, sendActions = [], ordered = {}} = {}) => { this.isValidDraft.andReturn(isValid) return mount( ) } it("renders without error", () => { const sendActionButton = render(this.draft); expect(sendActionButton.is(UndecoratedSendActionButton)).toBe(true); }); it("initializes with the default and shows the standard Send option", () => { const sendActionButton = render(this.draft); const button = sendActionButton.find('button').first(); expect(button.text()).toEqual('Send'); }); it("is a single button when there are no send actions", () => { const sendActionButton = render(this.draft, {sendActions: []}); const dropdowns = sendActionButton.find(ButtonDropdown); const buttons = sendActionButton.find('button'); expect(buttons.length).toBe(1); expect(dropdowns.length).toBe(0); expect(buttons.first().text()).toBe('Send'); }); it("is a dropdown when there's more than one send action", () => { const sendActionButton = render(this.draft, { sendActions: [GoodSendAction], }); const dropdowns = sendActionButton.find(ButtonDropdown); const buttons = sendActionButton.find('button'); expect(buttons.length).toBe(0); expect(dropdowns.length).toBe(1); expect(dropdowns.first().prop('primaryTitle')).toBe('Send'); }); it("has the correct primary item", () => { const sendActionButton = render(this.draft, { sendActions: [GoodSendAction, SecondSendAction], ordered: {preferred: SecondSendAction, rest: [DefaultSendAction, GoodSendAction]}, }); const dropdown = sendActionButton.find(ButtonDropdown).first(); expect(dropdown.prop('primaryTitle')).toBe("Second Send Action"); }); it("still renders with a null iconUrl and doesn't show the image", () => { const sendActionButton = render(this.draft, { sendActions: [NoIconUrl], ordered: {preferred: NoIconUrl, rest: [DefaultSendAction]}, }); const dropdowns = sendActionButton.find(ButtonDropdown); const buttons = sendActionButton.find('button'); const icons = sendActionButton.find(RetinaImg) expect(buttons.length).toBe(0); expect(dropdowns.length).toBe(1); expect(icons.length).toBe(3); }); it("sends a draft by default if no extra actions present", () => { const sendActionButton = render(this.draft); const button = sendActionButton.find('button').first(); button.simulate('click') expect(this.isValidDraft).toHaveBeenCalled(); expect(Actions.sendDraft).toHaveBeenCalledWith(this.draft.clientId, 'send'); }); it("doesn't send a draft if the isValidDraft fails", () => { const sendActionButton = render(this.draft, {isValid: false}); const button = sendActionButton.find('button').first(); button.simulate('click') expect(this.isValidDraft).toHaveBeenCalled(); expect(Actions.sendDraft).not.toHaveBeenCalled(); }); it("does the preferred action when more than one action present", () => { const sendActionButton = render(this.draft, { sendActions: [GoodSendAction], ordered: {preferred: GoodSendAction, rest: [DefaultSendAction]}, }); const button = sendActionButton.find('.primary-item').first(); button.simulate('click') expect(this.isValidDraft).toHaveBeenCalled(); expect(Actions.sendDraft).toHaveBeenCalledWith(this.draft.clientId, 'good-send-action'); }); }); ================================================ FILE: packages/client-app/internal_packages/composer/stylesheets/composer.less ================================================ // The ui-variables file is provided by base themes provided by N1. @import "ui-variables"; @import "ui-mixins"; @import "buttons"; @compose-width: 800px; @compose-min-height: 70px; @blurred-primary-color: mix(@background-primary, #ffbb00, 96%); @blurred-off-primary-color: mix(@background-off-primary, #ffbb00, 96%); body.platform-win32 { .composer-inner-wrap { .composer-drop-cover { border-radius: 0; } .composer-action-bar-wrap { border-radius: 0; } input, input:focus { box-shadow: none; } } } .action-bar-cover-gen() { .action-bar-cover { background-image: -webkit-linear-gradient(left, fade(@action-bar-bg, 0) 0%, @action-bar-bg 10%); } } // Used to allow the click targets to extend into the margins .composer-field-bottom-border() { width: calc(~"100% - 44px"); height: 1px; position: absolute; bottom: 0; left: 23px; content: " "; background: @border-color-divider; } .composer-inner-wrap { position: relative; height: 100%; display: flex; flex-direction: column; .composer-drop-cover { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1000; background: rgba(255,255,255,0.7); border-radius: @border-radius-base; border: 4px dashed lighten(@gray, 30%); text-align: center; line-height:2.3em; pointer-events: none; .centered { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); color: lighten(@gray, 20%); font-weight: 500; font-size:1.1em; img { margin: auto; display:block; margin-bottom:20px; background-color: lighten(@gray, 20%); } } } .inline-image-upload-container { display: inline-block; .nylas-attachment-item.image-attachment-item { margin: 0; max-width: 100%; min-width: 0; } } .composer-action-bar-wrap { @action-bar-bg: @background-off-primary; position: relative; width: 100%; background: @action-bar-bg; border-top: 1px solid darken(@background-off-primary, 7%); box-shadow: inset 0 2px 1px rgba(0,0,0,0.03); border-bottom: 0; border-radius: @border-radius-base; .action-bar-cover-gen; // Buttons in the composer footer .btn.btn-toolbar:not(.btn-emphasis) { background: transparent; box-shadow: 0 0 0; margin: 0; padding: 0 9px; white-space: nowrap; img.content-mask { background-color: fadeout(mix(@btn-default-text-color, @component-active-color, 88%), 30%); } &:hover { img.content-mask { background-color: fadeout(mix(@btn-default-text-color, @component-active-color, 88%), 5%); } } &.btn-enabled { color: @component-active-color; img.content-mask { background-color: @component-active-color; } } } .btn-send { margin-right: 10px; white-space: nowrap; } .composer-action-bar-content { display:flex; margin: 0 auto; flex-direction:row; max-width: @compose-width; padding: 9px 22.5px; .composer-action-bar-plugins { flex-wrap: wrap; } } .action-bar-animation-wrap { position: relative; overflow: hidden; .composer-action-bar-plugins { opacity: 0; transition: opacity 30ms; } .action-bar-cover { transition: left 200ms ease-out; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; } &.plugins-loaded { .composer-action-bar-plugins { opacity: 1; } .action-bar-cover { left: 100%; } } } } .composer-content-wrap { padding: 0; flex: 1; display: flex; position: relative; flex-flow: column; } .composer-centered { display:flex; position: relative; flex-direction: column; flex: 1; width: 100%; max-width: @compose-width; margin: 0 auto; padding-top: @spacing-standard * 0.7; } .text-actions { text-align: right; line-height: 1.4; position: relative; top: -3px; } .composer-body-wrap { padding: 0 0 5px 0; } .composer-header-actions { position: relative; float: right; z-index: 2; cursor: default; padding-right: @spacing-standard + @spacing-half; padding-top: 12px; .action { color: @text-color-very-subtle; img.content-mask { background-color: @text-color-very-subtle; } font-size: @font-size-small; padding: 10px 6px; &:first-child { padding-left: @spacing-standard; } &:last-child { padding-right: 0; } &:hover { color: @text-color-link; img.content-mask { background-color: @text-color-link; } cursor: default; } } } input, textarea { color: @text-color; position: relative; display: block; background: inherit; width: 100%; resize: none; border: none; } .composer-field-label { color: @text-color-very-subtle; float: left; padding-top: 13px; display: block; &:hover { cursor: default; } } .collapsed-composer-participants { position: relative; margin: 0 23px; border-bottom: 1px solid @border-color-divider; flex-shrink:0; color: @text-color-very-subtle; padding: 10px 0 10px 0; .collapsed-contact { padding-right: 0.25em; color: @text-color; &:after { content: "," } &:last-child:after { content: "" } } .num-remaining.token { color: @text-color; padding-right: 12px; margin-left: 0; margin-top: 2px; } .num-remaining-wrap { position: absolute; right: -3px; z-index: 2; top: 6px; .show-more-fade { position: absolute; width: 190px; height: 32px; right: 0; top: 0; background: linear-gradient(to right, fade(@background-primary, 0%) 0%, fade(@background-primary, 100%) 40%); } } } .composer-subject { position: relative; margin: 0; flex-shrink:0; &:after { .composer-field-bottom-border; } // for Mail Merge div[contenteditable] { padding-left: 22px; padding-right: 22px; } input { display: inline-block; padding: 13px 22px 9px 22px; min-width: 5em; background-color: transparent; border: none; margin: 0; &::-webkit-input-placeholder { color: @text-color-very-subtle; } &:focus { box-shadow: none; } } } .compose-body-scroll { position:initial; .scroll-region-content .scroll-region-content-inner { min-height: 100%; display: flex; } } .compose-body { flex: 1; cursor: text; overflow-x: auto; position: relative; margin: 0; .quoted-text-control { position: relative; // The quoted-text-control has no top margin since the // div[contentedtiable] has 10px of bottom padding. It's better to // put the padding on the contenteditable so the bottom looks nice // in popout windows when there's no quoted text control. margin: 0 @spacing-standard @spacing-standard 22px; .remove-quoted-text { display: none; cursor: pointer; position: absolute; z-index: 2; right: -6px; top: -6px; border-radius: 0 0 0 3px; &:active { background: none; -webkit-filter: brightness(95%); } img { height: 24px; } } &:hover .remove-quoted-text { display: block; } } // All of the padding is placed on the contenteditable itself so // clicks on the margins register within the region. div[contenteditable] { padding: 20px 22px 0 22px; min-height: @compose-min-height; } } .composer-footer-region { cursor: default; &:hover { cursor: default; } } // TODO FIXME DRY From stylesheets/message-list.less .attachments-area { padding: 0; margin: 0 8px; } } // Overrides for the full-window popout composer .composer-full-window { width: 100%; height: 100%; .composer-outer-wrap { width: 100%; height: 100%; } .composer-inner-wrap { .composer-action-bar-wrap { @action-bar-bg: darken(@background-primary, 1%); background: @action-bar-bg; border-top: 1px solid darken(@background-primary, 8%); box-shadow: inset 0 1px 2px rgba(0,0,0,0.03); .action-bar-cover-gen; } .composer-action-bar-content { padding: 9px 13.5px 9px 22.5px; } .compose-body { margin-bottom: 0; position: relative; } } .compose-body { div[contenteditable] { min-height: @line-height-computed; } } } // Overrides for the composer in a message-list #message-list { .message-item-wrap { .message-item-white-wrap.composer-outer-wrap { background: @blurred-primary-color; .btn.btn-toolbar.btn-trash { padding-right: 0; } .show-more-fade { background: linear-gradient(to right, fade(@blurred-primary-color, 0%) 0%, fade(@blurred-primary-color, 100%) 40%); } .composer-action-bar-wrap { @action-bar-bg: @blurred-off-primary-color; background: @action-bar-bg; .action-bar-cover-gen; } } .message-item-white-wrap.composer-outer-wrap.focused { box-shadow: 0 0 0.5px rgba(0, 0, 0, 0.28), 0 1px 1.5px rgba(0, 0, 0, 0.08), 0 0 3px @accent-primary; background-color: @background-primary; .show-more-fade { background: linear-gradient(to right, fade(@background-primary, 0%) 0%, fade(@background-primary, 100%) 40%); } .composer-action-bar-wrap { @action-bar-bg: @background-off-primary; background: @action-bar-bg; .action-bar-cover-gen; } } } } ////////////////////////////////// // participants-text-field.cjsx // ////////////////////////////////// .composer-participant-field { position: relative; margin: 0; flex-shrink: 0; min-height: 46px; color: @text-color; .tokenizing-field-wrap { padding: 0 22px; } .content-container { margin-left: 22px; width: calc(~"100% - 44px"); } .button-dropdown { .content-container { margin-left: 0; width: 100%; } } &:after { .composer-field-bottom-border; } &.from-field { padding: 0 22px; } .from-single-name { &:hover { cursor: default; } } .button-dropdown { margin-left: 10px; padding-top: 11px; vertical-align: -webkit-baseline-middle; .primary-item, .only-item { line-height: 2em; } &:hover { .primary-item, .only-item { border-radius: @border-radius-base; } } .secondary-items { border-radius: @border-radius-base; } .item { .contact.is-alias { font-style: italic; padding-left: @padding-small-horizontal; border-left: 2px solid @border-color-divider; margin-left: 2px; } } } .participant { display: flex; align-items: center; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; .participant-primary { font-weight: @font-weight-semi-bold; } .participant-secondary { color: @text-color-very-subtle; } } .tokenizing-field-input { margin-left: 2.8em; } } ////////////////////////////////// // Overlaid Components // ////////////////////////////////// .overlaid-components { position: absolute; top: 0; left: 0; width: 100%; height: 0; line-height: 1.4; // must match contenteditable container overflow: visible; z-index: 1; } img.n1-overlaid-component-anchor-container { border: 0; vertical-align: baseline; } .toggle-preview { position: absolute; top: 5px; right: 20px; font-size: @font-size-smaller; opacity: 0.3; cursor: pointer; &:hover { cursor: pointer; opacity: 1; } } ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/categorized-emoji.es6 ================================================ const categorizedEmojiList = { 'People': [ 'grinning', 'grimacing', 'grin', 'joy', 'smiley', 'smile', 'sweat_smile', 'laughing', 'innocent', 'wink', 'blush', 'slightly_smiling_face', 'upside_down_face', 'relaxed', 'yum', 'relieved', 'heart_eyes', 'kissing_heart', 'kissing', 'kissing_smiling_eyes', 'kissing_closed_eyes', 'stuck_out_tongue_winking_eye', 'stuck_out_tongue_closed_eyes', 'stuck_out_tongue', 'money_mouth_face', 'nerd_face', 'sunglasses', 'hugging_face', 'smirk', 'no_mouth', 'neutral_face', 'expressionless', 'unamused', 'face_with_rolling_eyes', 'thinking_face', 'flushed', 'disappointed', 'worried', 'angry', 'rage', 'pensive', 'confused', 'slightly_frowning_face', 'white_frowning_face', 'persevere', 'confounded', 'tired_face', 'weary', 'triumph', 'open_mouth', 'scream', 'fearful', 'cold_sweat', 'hushed', 'frowning', 'anguished', 'cry', 'disappointed_relieved', 'sleepy', 'sweat', 'sob', 'dizzy_face', 'astonished', 'zipper_mouth_face', 'mask', 'face_with_thermometer', 'face_with_head_bandage', 'sleeping', 'zzz', 'poop', 'smiling_imp', 'imp', 'japanese_ogre', 'japanese_goblin', 'skull', 'ghost', 'alien', 'robot_face', 'smiley_cat', 'smile_cat', 'joy_cat', 'heart_eyes_cat', 'smirk_cat', 'kissing_cat', 'scream_cat', 'crying_cat_face', 'pouting_cat', 'raised_hands', 'clap', 'wave', 'thumbsup', 'thumbsdown', 'punch', 'fist', 'v', 'ok_hand', 'hand', 'open_hands', 'muscle', 'pray', 'point_up', 'point_up_2', 'point_down', 'point_left', 'point_right', 'middle_finger', 'raised_hand_with_fingers_splayed', 'the_horns', 'spock-hand', 'writing_hand', 'nail_care', 'lips', 'tongue', 'ear', 'nose', 'eye', 'eyes', 'bust_in_silhouette', 'busts_in_silhouette', 'speaking_head_in_silhouette', 'baby', 'boy', 'girl', 'man', 'woman', 'person_with_blond_hair', 'older_man', 'older_woman', 'man_with_gua_pi_mao', 'man_with_turban', 'cop', 'construction_worker', 'guardsman', 'sleuth_or_spy', 'santa', 'angel', 'princess', 'bride_with_veil', 'walking', 'running', 'dancer', 'dancers', 'couple', 'two_men_holding_hands', 'two_women_holding_hands', 'bow', 'information_desk_person', 'no_good', 'ok_woman', 'raising_hand', 'person_with_pouting_face', 'person_frowning', 'haircut', 'massage', 'couple_with_heart', 'woman-heart-woman', 'man-heart-man', 'couplekiss', 'woman-kiss-woman', 'man-kiss-man', 'family', 'man-woman-girl', 'man-woman-girl-boy', 'man-woman-boy-boy', 'man-woman-girl-girl', 'woman-woman-boy', 'woman-woman-girl', 'woman-woman-girl-boy', 'woman-woman-boy-boy', 'woman-woman-girl-girl', 'man-man-boy', 'man-man-girl', 'man-man-girl-boy', 'man-man-boy-boy', 'man-man-girl-girl', 'womans_clothes', 'shirt', 'jeans', 'necktie', 'dress', 'bikini', 'kimono', 'lipstick', 'kiss', 'footprints', 'high_heel', 'sandal', 'boot', 'mans_shoe', 'athletic_shoe', 'womans_hat', 'tophat', 'helmet_with_white_cross', 'mortar_board', 'crown', 'school_satchel', 'pouch', 'purse', 'handbag', 'briefcase', 'eyeglasses', 'dark_sunglasses', 'ring', 'closed_umbrella', ], 'Nature': [ 'dog', 'cat', 'mouse', 'hamster', 'rabbit', 'bear', 'panda_face', 'koala', 'tiger', 'lion_face', 'cow', 'pig', 'pig_nose', 'frog', 'octopus', 'monkey_face', 'see_no_evil', 'hear_no_evil', 'speak_no_evil', 'monkey', 'chicken', 'penguin', 'bird', 'baby_chick', 'hatching_chick', 'hatched_chick', 'wolf', 'boar', 'horse', 'unicorn_face', 'bee', 'bug', 'snail', 'beetle', 'ant', 'spider', 'scorpion', 'crab', 'snake', 'turtle', 'tropical_fish', 'fish', 'blowfish', 'dolphin', 'whale', 'whale2', 'crocodile', 'leopard', 'tiger2', 'water_buffalo', 'ox', 'cow2', 'dromedary_camel', 'camel', 'elephant', 'goat', 'ram', 'sheep', 'racehorse', 'pig2', 'rat', 'mouse2', 'rooster', 'turkey', 'dove_of_peace', 'dog2', 'poodle', 'cat2', 'rabbit2', 'chipmunk', 'paw_prints', 'dragon', 'dragon_face', 'cactus', 'christmas_tree', 'evergreen_tree', 'deciduous_tree', 'palm_tree', 'seedling', 'herb', 'shamrock', 'four_leaf_clover', 'bamboo', 'tanabata_tree', 'leaves', 'fallen_leaf', 'maple_leaf', 'ear_of_rice', 'hibiscus', 'sunflower', 'rose', 'tulip', 'blossom', 'cherry_blossom', 'bouquet', 'mushroom', 'chestnut', 'jack_o_lantern', 'shell', 'spider_web', 'earth_americas', 'earth_africa', 'earth_asia', 'full_moon', 'waning_gibbous_moon', 'last_quarter_moon', 'waning_crescent_moon', 'new_moon', 'waxing_crescent_moon', 'first_quarter_moon', 'moon', 'new_moon_with_face', 'full_moon_with_face', 'first_quarter_moon_with_face', 'last_quarter_moon_with_face', 'sun_with_face', 'crescent_moon', 'star', 'star2', 'dizzy', 'sparkles', 'comet', 'sunny', 'mostly_sunny', 'partly_sunny', 'barely_sunny', 'partly_sunny_rain', 'cloud', 'rain_cloud', 'thunder_cloud_and_rain', 'lightning', 'zap', 'fire', 'boom', 'snowflake', 'snow_cloud', 'showman', 'snowman', 'wind_blowing_face', 'dash', 'tornado', 'fog', 'umbrella', 'droplet', 'sweat_drops', 'ocean', ], 'Food and Drink': [ 'green_apple', 'apple', 'pear', 'tangerine', 'lemon', 'banana', 'watermelon', 'grapes', 'strawberry', 'melon', 'cherries', 'peach', 'pineapple', 'tomato', 'eggplant', 'hot_pepper', 'corn', 'sweet_potato', 'honey_pot', 'bread', 'cheese_wedge', 'poultry_leg', 'meat_on_bone', 'fried_shrimp', 'egg', 'hamburger', 'fries', 'hotdog', 'pizza', 'spaghetti', 'taco', 'burrito', 'ramen', 'stew', 'fish_cake', 'sushi', 'bento', 'curry', 'rice_ball', 'rice', 'rice_cracker', 'oden', 'dango', 'shaved_ice', 'ice_cream', 'icecream', 'cake', 'birthday', 'custard', 'candy', 'lollipop', 'chocolate_bar', 'popcorn', 'doughnut', 'cookie', 'beer', 'beers', 'wine_glass', 'cocktail', 'tropical_drink', 'champagne', 'sake', 'tea', 'coffee', 'baby_bottle', 'fork_and_knife', 'knife_fork_plate', ], 'Activity': [ 'soccer', 'basketball', 'football', 'baseball', 'tennis', 'volleyball', 'rugby_football', '8ball', 'golf', 'golfer', 'table_tennis_paddle_and_ball', 'badminton_racquet_and_shuttlecock', 'ice_hockey_stick_and_puck', 'field_hockey_stick_and_ball', 'cricket_bat_and_ball', 'ski', 'skier', 'snowboarder', 'ice_skate', 'bow_and_arrow', 'fishing_pole_and_fish', 'rowboat', 'swimmer', 'surfer', 'bath', 'person_with_ball', 'weight_lifter', 'bicyclist', 'mountain_bicyclist', 'horse_racing', 'man_in_business_suit_levitating', 'trophy', 'running_shirt_with_sash', 'sports_medal', 'medal', 'reminder_ribbon', 'rosette', 'ticket', 'admission_tickets', 'performing_arts', 'art', 'circus_tent', 'microphone', 'headphones', 'musical_score', 'musical_keyboard', 'saxophone', 'trumpet', 'guitar', 'violin', 'clapper', 'video_game', 'space_invader', 'dart', 'game_die', 'slot_machine', 'bowling', ], 'Travel and Places': [ 'car', 'taxi', 'blue_car', 'bus', 'trolleybus', 'racing_car', 'police_car', 'ambulance', 'fire_engine', 'minibus', 'truck', 'articulated_lorry', 'tractor', 'racing_motorcycle', 'bike', 'rotating_light', 'oncoming_police_car', 'oncoming_bus', 'oncoming_automobile', 'oncoming_taxi', 'aerial_tramway', 'mountain_cableway', 'suspension_railway', 'railway_car', 'train', 'monorail', 'bullettrain_side', 'bullettrain_front', 'light_rail', 'mountain_railway', 'steam_locomotive', 'train2', 'metro', 'tram', 'station', 'helicopter', 'small_airplane', 'airplane', 'airplane_departure', 'airplane_arriving', 'boat', 'motor_boat', 'speedboat', 'ferry', 'passenger_ship', 'rocket', 'satellite', 'seat', 'anchor', 'construction', 'fuelpump', 'busstop', 'vertical_traffic_light', 'traffic_light', 'checkered_flag', 'ship', 'ferris_wheel', 'roller_coaster', 'carousel_horse', 'building_construction', 'foggy', 'tokyo_tower', 'factory', 'fountain', 'rice_scene', 'mountain', 'snow_capped_mountain', 'mount_fuji', 'volcano', 'japan', 'camping', 'tent', 'national_park', 'motorway', 'railway_track', 'sunrise', 'sunrise_over_mountains', 'desert', 'beach_with_umbrella', 'desert_island', 'city_sunrise', 'city_sunset', 'cityscape', 'night_with_stars', 'bridge_at_night', 'milky_way', 'stars', 'sparkler', 'fireworks', 'rainbow', 'house_buildings', 'european_castle', 'japanese_castle', 'stadium', 'statue_of_liberty', 'house', 'house_with_garden', 'derelict_house_building', 'office', 'department_store', 'post_office', 'european_post_office', 'hospital', 'bank', 'hotel', 'convenience_store', 'school', 'love_hotel', 'wedding', 'classical_building', 'church', 'mosque', 'synagogue', 'kaaba', 'shinto_shrine', ], 'Objects': [ 'watch', 'iphone', 'calling', 'computer', 'keyboard', 'desktop_computer', 'printer', 'three_button_mouse', 'trackball', 'joystick', 'compression', 'minidisc', 'floppy_disk', 'cd', 'dvd', 'vhs', 'camera', 'camera_with_flash', 'video_camera', 'movie_camera', 'film_projector', 'film_frames', 'telephone_receiver', 'phone', 'pager', 'fax', 'tv', 'radio', 'studio_microphone', 'level_slider', 'control_knobs', 'stopwatch', 'timer_clock', 'alarm_clock', 'mantelpiece_clock', 'hourglass_flowing_sand', 'hourglass', 'battery', 'electric_plug', 'bulb', 'flashlight', 'candle', 'wastebasket', 'oil_drum', 'money_with_wings', 'dollar', 'yen', 'euro', 'pound', 'moneybag', 'credit_card', 'gem', 'scales', 'wrench', 'hammer', 'hammer_and_pick', 'hammer_and_wrench', 'pick', 'nut_and_bolt', 'gear', 'chains', 'gun', 'bomb', 'knife', 'dagger_knife', 'crossed_swords', 'shield', 'smoking', 'skull_and_crossbones', 'coffin', 'funeral_urn', 'amphora', 'crystal_ball', 'prayer_beads', 'barber', 'alembic', 'telescope', 'microscope', 'hole', 'pill', 'syringe', 'thermometer', 'label', 'bookmark', 'toilet', 'shower', 'bathtub', 'key', 'old_key', 'couch_and_lamp', 'sleeping_accommodation', 'bed', 'door', 'bellhop_bell', 'frame_with_picture', 'world_map', 'umbrella_on_ground', 'moyai', 'shopping_bags', 'balloon', 'flags', 'ribbon', 'gift', 'confetti_ball', 'tada', 'dolls', 'wind_chime', 'crossed_flags', 'izakaya_lantern', 'envelope', 'envelope_with_arrow', 'incoming_envelope', 'e-mail', 'love_letter', 'postbox', 'mailbox_closed', 'mailbox', 'mailbox_with_mail', 'mailbox_with_no_mail', 'package', 'postal_horn', 'inbox_tray', 'outbox_tray', 'scroll', 'page_with_curl', 'bookmark_tabs', 'bar_chart', 'chart_with_upwards_trend', 'chart_with_downwards_trend', 'page_facing_up', 'date', 'calendar', 'spiral_calendar_pad', 'card_index', 'card_file_box', 'ballot_box_with_ballot', 'file_cabinet', 'clipboard', 'spiral_note_pad', 'file_folder', 'open_file_folder', 'card_index_dividers', 'rolled_up_newspaper', 'newspaper', 'notebook', 'closed_book', 'green_book', 'blue_book', 'orange_book', 'notebook_with_decorative_cover', 'ledger', 'books', 'book', 'link', 'paperclip', 'linked_paperclips', 'scissors', 'triangular_ruler', 'straight_ruler', 'pushpin', 'round_pushpin', 'triangular_flag_on_post', 'waving_white_flag', 'waving_black_flag', 'closed_lock_with_key', 'lock', 'unlock', 'lock_with_ink_pen', 'lower_left_ballpoint_pen', 'lower_left_fountain_pen', 'black_nib', 'memo', 'pencil2', 'lower_left_crayon', 'lower_left_paintbrush', 'mag', 'mag_right', ], 'Symbols': [ 'heart', 'yellow_heart', 'green_heart', 'blue_heart', 'purple_heart', 'broken_heart', 'heavy_heart_exclamation_mark_ornament', 'two_hearts', 'revolving_hearts', 'heartbeat', 'heartpulse', 'sparkling_heart', 'cupid', 'gift_heart', 'heart_decoration', 'peace_symbol', 'latin_cross', 'star_and_crescent', 'om_symbol', 'wheel_of_dharma', 'star_of_david', 'six_pointed_star', 'menorah_with_nine_branches', 'yin_yang', 'orthodox_cross', 'place_of_worship', 'ophiuchus', 'aries', 'taurus', 'gemini', 'cancer', 'leo', 'virgo', 'libra', 'scorpius', 'sagittarius', 'capricorn', 'aquarius', 'pisces', 'id', 'atom_symbol', 'u7a7a', 'u5272', 'radioactive_sign', 'biohazard_sign', 'mobile_phone_off', 'vibration_mode', 'u6709', 'u7121', 'u7533', 'u55b6', 'u6708', 'eight_pointed_black_star', 'vs', 'accept', 'white_flower', 'ideograph_advantage', 'secret', 'congratulations', 'u5408', 'u6e80', 'u7981', 'a', 'b', 'ab', 'cl', 'o2', 'sos', 'no_entry', 'name_badge', 'no_entry_sign', 'x', 'o', 'anger', 'hotsprings', 'no_pedestrians', 'do_not_litter', 'no_bicycles', 'non-potable_water', 'underage', 'no_mobile_phones', 'exclamation', 'grey_exclamation', 'question', 'grey_question', 'bangbang', 'interrobang', '100', 'low_brightness', 'high_brightness', 'trident', 'fleur_de_lis', 'part_alternation_mark', 'warning', 'children_crossing', 'beginner', 'recycle', 'u6307', 'chart', 'sparkle', 'eight_spoked_asterisk', 'negative_squared_cross_mark', 'white_check_mark', 'diamond_shape_with_a_dot_inside', 'cyclone', 'loop', 'globe_with_meridians', 'm', 'atm', 'sa', 'passport_control', 'customs', 'baggage_claim', 'left_luggage', 'wheelchair', 'no_smoking', 'wc', 'parking', 'potable_water', 'mens', 'womens', 'baby_symbol', 'restroom', 'put_litter_in_its_place', 'cinema', 'signal_strength', 'koko', 'ng', 'ok', 'up', 'cool', 'new', 'free', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'keycap_ten', 'keycap_star', '1234', 'arrow_forward', 'double_vertical_bar', 'black_right_pointing_triangle_with_double_vertical_bar', 'black_square_for_stop', 'black_circle_for_record', 'black_right_pointing_double_triangle_with_vertical_bar', 'black_left_pointing_double_triangle_with_vertical_bar', 'fast_forward', 'rewind', 'twisted_rightwards_arrows', 'repeat', 'repeat_one', 'arrow_backward', 'arrow_up_small', 'arrow_down_small', 'arrow_double_up', 'arrow_double_down', 'arrow_right', 'arrow_left', 'arrow_up', 'arrow_down', 'arrow_upper_right', 'arrow_lower_right', 'arrow_lower_left', 'arrow_upper_left', 'arrow_up_down', 'left_right_arrow', 'arrows_counterclockwise', 'arrow_right_hook', 'leftwards_arrow_with_hook', 'arrow_heading_up', 'arrow_heading_down', 'hash', 'information_source', 'abc', 'abcd', 'capital_abcd', 'symbols', 'musical_note', 'notes', 'wavy_dash', 'curly_loop', 'heavy_check_mark', 'arrows_clockwise', 'heavy_plus_sign', 'heavy_minus_sign', 'heavy_division_sign', 'heavy_multiplication_x', 'heavy_dollar_sign', 'currency_exchange', 'copyright', 'registered', 'tm', 'end', 'back', 'on', 'top', 'soon', 'ballot_box_with_check', 'radio_button', 'white_circle', 'black_circle', 'red_circle', 'large_blue_circle', 'small_orange_diamond', 'small_blue_diamond', 'large_orange_diamond', 'large_blue_diamond', 'small_red_triangle', 'black_small_square', 'white_small_square', 'black_large_square', 'white_large_square', 'small_red_triangle_down', 'black_medium_square', 'white_medium_square', 'black_medium_small_square', 'white_medium_small_square', 'black_square_button', 'white_square_button', 'speaker', 'sound', 'loud_sound', 'mute', 'mega', 'loudspeaker', 'bell', 'no_bell', 'black_joker', 'mahjong', 'spades', 'clubs', 'hearts', 'diamonds', 'flower_playing_cards', 'thought_balloon', 'right_anger_bubble', 'speech_balloon', 'left_speech_bubble', 'clock1', 'clock2', 'clock3', 'clock4', 'clock5', 'clock6', 'clock7', 'clock8', 'clock9', 'clock10', 'clock11', 'clock12', 'clock130', 'clock230', 'clock330', 'clock430', 'clock530', 'clock630', 'clock730', 'clock830', 'clock930', 'clock1030', 'clock1130', 'clock1230', ], 'Flags': [ 'flag-ac', 'flag-ad', 'flag-ae', 'flag-af', 'flag-ag', 'flag-ai', 'flag-al', 'flag-am', 'flag-ao', 'flag-aq', 'flag-ar', 'flag-as', 'flag-at', 'flag-au', 'flag-aw', 'flag-ax', 'flag-az', 'flag-ba', 'flag-bb', 'flag-bd', 'flag-be', 'flag-bf', 'flag-bg', 'flag-bh', 'flag-bi', 'flag-bj', 'flag-bl', 'flag-bm', 'flag-bn', 'flag-bo', 'flag-bq', 'flag-br', 'flag-bs', 'flag-bt', 'flag-bv', 'flag-bw', 'flag-by', 'flag-bz', 'flag-ca', 'flag-cc', 'flag-cd', 'flag-cf', 'flag-cg', 'flag-ch', 'flag-ci', 'flag-ck', 'flag-cl', 'flag-cm', 'flag-cn', 'flag-co', 'flag-cp', 'flag-cr', 'flag-cu', 'flag-cv', 'flag-cw', 'flag-cx', 'flag-cy', 'flag-cz', 'flag-de', 'flag-dg', 'flag-dj', 'flag-dk', 'flag-dm', 'flag-do', 'flag-dz', 'flag-ea', 'flag-ec', 'flag-ee', 'flag-eg', 'flag-eh', 'flag-er', 'flag-es', 'flag-et', 'flag-eu', 'flag-fi', 'flag-fj', 'flag-fk', 'flag-fm', 'flag-fo', 'flag-fr', 'flag-ga', 'flag-gb', 'flag-gd', 'flag-ge', 'flag-gf', 'flag-gg', 'flag-gh', 'flag-gi', 'flag-gl', 'flag-gm', 'flag-gn', 'flag-gp', 'flag-gq', 'flag-gr', 'flag-gs', 'flag-gt', 'flag-gu', 'flag-gw', 'flag-gy', 'flag-hk', 'flag-hm', 'flag-hn', 'flag-hr', 'flag-ht', 'flag-hu', 'flag-ic', 'flag-id', 'flag-ie', 'flag-il', 'flag-im', 'flag-in', 'flag-io', 'flag-iq', 'flag-ir', 'flag-is', 'flag-it', 'flag-je', 'flag-jm', 'flag-jo', 'flag-jp', 'flag-ke', 'flag-kg', 'flag-kh', 'flag-ki', 'flag-km', 'flag-kn', 'flag-kp', 'flag-kr', 'flag-kw', 'flag-ky', 'flag-kz', 'flag-la', 'flag-lb', 'flag-lc', 'flag-li', 'flag-lk', 'flag-lr', 'flag-ls', 'flag-lt', 'flag-lu', 'flag-lv', 'flag-ly', 'flag-ma', 'flag-mc', 'flag-md', 'flag-me', 'flag-mf', 'flag-mg', 'flag-mh', 'flag-mk', 'flag-ml', 'flag-mm', 'flag-mn', 'flag-mo', 'flag-mp', 'flag-mq', 'flag-mr', 'flag-ms', 'flag-mt', 'flag-mu', 'flag-mv', 'flag-mw', 'flag-mx', 'flag-my', 'flag-mz', 'flag-na', 'flag-nc', 'flag-ne', 'flag-nf', 'flag-ng', 'flag-ni', 'flag-nl', 'flag-no', 'flag-np', 'flag-nr', 'flag-nu', 'flag-nz', 'flag-om', 'flag-pa', 'flag-pe', 'flag-pf', 'flag-pg', 'flag-ph', 'flag-pk', 'flag-pl', 'flag-pm', 'flag-pn', 'flag-pr', 'flag-ps', 'flag-pt', 'flag-pw', 'flag-py', 'flag-qa', 'flag-re', 'flag-ro', 'flag-rs', 'flag-ru', 'flag-rw', 'flag-sa', 'flag-sb', 'flag-sc', 'flag-sd', 'flag-se', 'flag-sg', 'flag-sh', 'flag-si', 'flag-sj', 'flag-sk', 'flag-sl', 'flag-sm', 'flag-sn', 'flag-so', 'flag-sr', 'flag-ss', 'flag-st', 'flag-sv', 'flag-sx', 'flag-sy', 'flag-sz', 'flag-ta', 'flag-tc', 'flag-td', 'flag-tf', 'flag-tg', 'flag-th', 'flag-tj', 'flag-tk', 'flag-tl', 'flag-tm', 'flag-tn', 'flag-to', 'flag-tr', 'flag-tt', 'flag-tv', 'flag-tw', 'flag-tz', 'flag-ua', 'flag-ug', 'flag-um', 'flag-us', 'flag-uy', 'flag-uz', 'flag-va', 'flag-vc', 'flag-ve', 'flag-vg', 'flag-vi', 'flag-vn', 'flag-vu', 'flag-wf', 'flag-ws', 'flag-xk', 'flag-ye', 'flag-yt', 'flag-za', 'flag-zm', 'flag-zw', ], } export default categorizedEmojiList ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-actions.es6 ================================================ import Reflux from 'reflux'; const EmojiActions = Reflux.createActions([ "selectEmoji", "useEmoji", ]); for (const key of Object.keys(EmojiActions)) { EmojiActions[key].sync = true; } export default EmojiActions; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-button-popover.jsx ================================================ import React from 'react'; import {findDOMNode} from 'react-dom'; import {Actions} from 'nylas-exports'; import {RetinaImg, ScrollRegion} from 'nylas-component-kit'; import EmojiStore from './emoji-store'; import EmojiActions from './emoji-actions'; import categorizedEmojiList from './categorized-emoji'; class EmojiButtonPopover extends React.Component { static displayName = 'EmojiButtonPopover'; constructor() { super(); const {categoryNames, categorizedEmoji, categoryPositions} = this.getStateFromStore(); this.state = { emojiName: "Emoji Picker", categoryNames: categoryNames, categorizedEmoji: categorizedEmoji, categoryPositions: categoryPositions, searchValue: "", activeTab: Object.keys(categorizedEmoji)[0], }; } componentDidMount() { this._mounted = true; this._emojiPreloadImage = new Image(); this.renderCanvas(); } componentWillUnmount() { this._emojiPreloadImage.onload = null; this._emojiPreloadImage = null; this._mounted = false; } onMouseDown = (event) => { const emojiName = this.calcEmojiByPosition(this.calcPosition(event)); if (!emojiName) return null; EmojiActions.selectEmoji({emojiName: emojiName, replaceSelection: false}); Actions.closePopover(); return null } onScroll = () => { const emojiContainer = document.querySelector(".emoji-finder-container .scroll-region-content"); const tabContainer = document.querySelector(".emoji-tabs"); tabContainer.className = emojiContainer.scrollTop ? "emoji-tabs shadow" : "emoji-tabs"; if (emojiContainer.scrollTop === 0) { this.setState({activeTab: Object.keys(this.state.categorizedEmoji)[0]}); } else { for (const category of Object.keys(this.state.categoryPositions)) { if (emojiContainer.scrollTop >= this.state.categoryPositions[category].top && emojiContainer.scrollTop <= this.state.categoryPositions[category].bottom) { this.setState({activeTab: category}); } } } } onHover = (event) => { const emojiName = this.calcEmojiByPosition(this.calcPosition(event)); if (emojiName) { this.setState({emojiName: emojiName}); } else { this.setState({emojiName: "Emoji Picker"}); } } onMouseOut = () => { this.setState({emojiName: "Emoji Picker"}); } onChange = (event) => { const searchValue = event.target.value; if (searchValue.length > 0) { const searchMatches = this.findSearchMatches(searchValue); this.setState({ categorizedEmoji: { 'Search Results': searchMatches, }, categoryPositions: { 'Search Results': { top: 25, bottom: 25 + Math.ceil(searchMatches.length / 8) * 24, }, }, searchValue: searchValue, activeTab: null, }, this.renderCanvas); } else { this.setState(this.getStateFromStore, () => { this.setState({ searchValue: searchValue, activeTab: Object.keys(this.state.categorizedEmoji)[0], }, this.renderCanvas); }); } } getStateFromStore = () => { let categorizedEmoji = categorizedEmojiList; const categoryPositions = {}; let categoryNames = [ 'People', 'Nature', 'Food and Drink', 'Activity', 'Travel and Places', 'Objects', 'Symbols', 'Flags', ]; const frequentlyUsedEmoji = EmojiStore.frequentlyUsedEmoji(); if (frequentlyUsedEmoji.length > 0) { categorizedEmoji = {'Frequently Used': frequentlyUsedEmoji}; for (const category of Object.keys(categorizedEmojiList)) { categorizedEmoji[category] = categorizedEmojiList[category]; } categoryNames = ["Frequently Used"].concat(categoryNames); } // Calculates where each category should be (variable because Frequently // Used may or may not be present) for (const name of categoryNames) { categoryPositions[name] = {top: 0, bottom: 0}; } let verticalPos = 25; for (const category of Object.keys(categoryPositions)) { const height = Math.ceil(categorizedEmoji[category].length / 8) * 24; categoryPositions[category].top = verticalPos; verticalPos += height; categoryPositions[category].bottom = verticalPos; verticalPos += 24; } return { categoryNames: categoryNames, categorizedEmoji: categorizedEmoji, categoryPositions: categoryPositions, }; } scrollToCategory(category) { const container = document.querySelector(".emoji-finder-container .scroll-region-content"); if (this.state.searchValue.length > 0) { this.setState({searchValue: ""}); this.setState(this.getStateFromStore, () => { this.renderCanvas(); container.scrollTop = this.state.categoryPositions[category].top + 16; }); } else { container.scrollTop = this.state.categoryPositions[category].top + 16; } this.setState({activeTab: category}) } findSearchMatches(searchValue) { // TODO: Find matches for aliases, too. const searchMatches = []; for (const category of Object.keys(categorizedEmojiList)) { categorizedEmojiList[category].forEach((emojiName) => { if (emojiName.indexOf(searchValue) !== -1) { searchMatches.push(emojiName); } }); } return searchMatches; } calcPosition(event) { const rect = event.target.getBoundingClientRect(); const position = { x: event.pageX - rect.left / 2, y: event.pageY - rect.top / 2, }; return position; } calcEmojiByPosition = (position) => { for (const category of Object.keys(this.state.categoryPositions)) { const LEFT_BOUNDARY = 8; const RIGHT_BOUNDARY = 204; const EMOJI_WIDTH = 24.5; const EMOJI_HEIGHT = 24; const EMOJI_PER_ROW = 8; if (position.x >= LEFT_BOUNDARY && position.x <= RIGHT_BOUNDARY && position.y >= this.state.categoryPositions[category].top && position.y <= this.state.categoryPositions[category].bottom) { const x = Math.round((position.x + 5) / EMOJI_WIDTH); const y = Math.round((position.y - this.state.categoryPositions[category].top + 10) / EMOJI_HEIGHT); const index = x + (y - 1) * EMOJI_PER_ROW - 1; return this.state.categorizedEmoji[category][index]; } } return null; } renderTabs() { const tabs = []; this.state.categoryNames.forEach((category) => { let className = `emoji-tab ${(category.replace(/ /g, '-')).toLowerCase()}` if (category === this.state.activeTab) { className += " active"; } tabs.push(
this.scrollToCategory(category)} />
); }); return tabs; } renderCanvas() { const canvas = findDOMNode(this.refs.emojiCanvas); const keys = Object.keys(this.state.categoryPositions); canvas.height = this.state.categoryPositions[keys[keys.length - 1]].bottom * 2; const ctx = canvas.getContext("2d"); ctx.font = "24px Nylas-Pro"; ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.clearRect(0, 0, canvas.width, canvas.height); const position = { x: 15, y: 45, } let idx = 0; const categoryNames = Object.keys(this.state.categorizedEmoji); const renderNextCategory = () => { if (!categoryNames[idx]) return; if (!this._mounted) return; this.renderCategory(categoryNames[idx], idx, ctx, position, renderNextCategory); idx += 1; } renderNextCategory(); } renderCategory(category, i, ctx, pos, callback) { const position = pos if (i > 0) { position.x = 18; position.y += 48; } ctx.fillText(category, position.x, position.y); position.x = 18; position.y += 48; const emojiNames = this.state.categorizedEmoji[category]; if (!emojiNames || emojiNames.length === 0) return; const emojiToDraw = emojiNames.map((emojiName, j) => { const x = position.x; const y = position.y; const src = EmojiStore.getImagePath(emojiName); if (position.x > 325 && j < this.state.categorizedEmoji[category].length - 1) { position.x = 18; position.y += 48; } else { position.x += 50; } return {src, x, y}; }); const drawEmojiAt = ({src, x, y} = {}) => { if (!src) { return; } this._emojiPreloadImage.onload = () => { this._emojiPreloadImage.onload = null; ctx.drawImage(this._emojiPreloadImage, x, y - 30, 32, 32); if (emojiToDraw.length === 0) { callback(); } else { drawEmojiAt(emojiToDraw.shift()); } } this._emojiPreloadImage.src = src; } drawEmojiAt(emojiToDraw.shift()); } render() { return (
{this.renderTabs()}
{this.state.emojiName}
); } } export default EmojiButtonPopover; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-button.jsx ================================================ import {Actions, React, ReactDOM} from 'nylas-exports'; import {RetinaImg} from 'nylas-component-kit'; import EmojiButtonPopover from './emoji-button-popover'; class EmojiButton extends React.Component { static displayName = 'EmojiButton'; onClick = () => { const buttonRect = ReactDOM.findDOMNode(this).getBoundingClientRect(); Actions.openPopover( , {originRect: buttonRect, direction: 'up'} ) } render() { return ( ); } } EmojiButton.containerStyles = { order: 2, }; export default EmojiButton; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-composer-extension.jsx ================================================ import {DOMUtils, ComposerExtension, RegExpUtils} from 'nylas-exports'; import emoji from 'node-emoji'; import EmojiStore from './emoji-store'; import EmojiActions from './emoji-actions'; import EmojiPicker from './emoji-picker'; class EmojiComposerExtension extends ComposerExtension { static selState = null; static onContentChanged = ({editor}) => { const sel = editor.currentSelection() const {emojiOptions, triggerWord} = EmojiComposerExtension._findEmojiOptions(sel); if (sel.anchorNode && sel.isCollapsed) { if (emojiOptions.length > 0) { const offset = sel.anchorOffset; if (!DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete")) { const anchorOffset = Math.max(sel.anchorOffset - triggerWord.length - 1, 0); editor.select(sel.anchorNode, anchorOffset, sel.focusNode, sel.focusOffset) editor.wrapSelection("n1-emoji-autocomplete"); editor.select(sel.anchorNode, offset, sel.anchorNode, offset); } } else { if (DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete")) { editor.unwrapNodeAndSelectAll(DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete")); editor.select(sel.anchorNode, sel.anchorOffset + triggerWord.length + 1, sel.focusNode, sel.focusOffset + triggerWord.length + 1); } } } else { if (DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete")) { editor.unwrapNodeAndSelectAll(DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete")); editor.select(sel.anchorNode, sel.anchorOffset + triggerWord.length, sel.focusNode, sel.focusOffset + triggerWord.length); } } }; static onBlur = ({editor}) => { EmojiComposerExtension.selState = editor.currentSelection().exportSelection(); }; static onFocus = ({editor}) => { if (EmojiComposerExtension.selState) { editor.select(EmojiComposerExtension.selState); EmojiComposerExtension.selState = null; } }; static toolbarComponentConfig = ({toolbarState}) => { const sel = toolbarState.selectionSnapshot; if (sel) { const {emojiOptions} = EmojiComposerExtension._findEmojiOptions(sel); if (emojiOptions.length > 0 && !toolbarState.dragging && !toolbarState.doubleDown) { const locationRefNode = DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete"); if (!locationRefNode) return null; const selectedEmoji = locationRefNode.getAttribute("selectedEmoji"); return { component: EmojiPicker, props: {emojiOptions, selectedEmoji}, locationRefNode: locationRefNode, width: EmojiComposerExtension._emojiPickerWidth(emojiOptions), height: EmojiComposerExtension._emojiPickerHeight(emojiOptions), hidePointer: true, } } } return null; }; static editingActions = () => { return [{ action: EmojiActions.selectEmoji, callback: EmojiComposerExtension._onSelectEmoji, }] }; static onKeyDown = ({editor, event}) => { const sel = editor.currentSelection() const {emojiOptions} = EmojiComposerExtension._findEmojiOptions(sel); if (emojiOptions.length > 0) { if (event.key === "ArrowDown" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowLeft") { event.preventDefault(); const moveToNext = (event.key === "ArrowDown" || event.key === "ArrowRight"); const emojiNameNode = DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete"); if (!emojiNameNode) return null; const selectedEmoji = emojiNameNode.getAttribute("selectedEmoji"); if (selectedEmoji) { const emojiIndex = emojiOptions.indexOf(selectedEmoji); if (emojiIndex < emojiOptions.length - 1 && moveToNext) { emojiNameNode.setAttribute("selectedEmoji", emojiOptions[emojiIndex + 1]); } else if (emojiIndex > 0 && !moveToNext) { emojiNameNode.setAttribute("selectedEmoji", emojiOptions[emojiIndex - 1]); } else { const index = moveToNext ? 0 : emojiOptions.length - 1; emojiNameNode.setAttribute("selectedEmoji", emojiOptions[index]); } } else { const index = moveToNext ? 1 : emojiOptions.length - 1; emojiNameNode.setAttribute("selectedEmoji", emojiOptions[index]); } } else if (event.key === "Enter" || event.key === "Tab") { event.preventDefault(); const emojiNameNode = DOMUtils.closest(sel.anchorNode, "n1-emoji-autocomplete"); if (!emojiNameNode) return null; let selectedEmoji = emojiNameNode.getAttribute("selectedEmoji"); if (!selectedEmoji) selectedEmoji = emojiOptions[0]; const args = { editor: editor, actionArg: { emojiName: selectedEmoji, replaceSelection: true, }, }; EmojiComposerExtension._onSelectEmoji(args); } } return null; }; static applyTransformsForSending = ({draftBodyRootNode}) => { const imgs = draftBodyRootNode.querySelectorAll('img') for (const imgEl of Array.from(imgs)) { const names = imgEl.className.split(' '); if (names[0] === 'emoji') { const emojiChar = emoji.get(names[1]); if (emojiChar) { imgEl.parentNode.replaceChild(document.createTextNode(emojiChar), imgEl); } } } } static unapplyTransformsForSending = ({draftBodyRootNode}) => { const treeWalker = document.createTreeWalker(draftBodyRootNode, NodeFilter.SHOW_TEXT); while (treeWalker.nextNode()) { const textNode = treeWalker.currentNode; const match = RegExpUtils.emojiRegex().exec(textNode.textContent); if (match) { const emojiPlusTrailingEl = textNode.splitText(match.index); emojiPlusTrailingEl.splitText(match.length); const emojiEl = emojiPlusTrailingEl; const imgEl = document.createElement('img'); const emojiName = emoji.which(match[0]) imgEl.className = `emoji ${emojiName}`; imgEl.src = EmojiStore.getImagePath(emojiName); imgEl.width = '14'; imgEl.height = '14'; imgEl.style.marginTop = '-5px'; emojiEl.parentNode.replaceChild(imgEl, emojiEl); } } } static _findEmojiOptions(sel) { if (sel.anchorNode && sel.anchorNode.nodeValue && sel.anchorNode.nodeValue.length > 0 && sel.isCollapsed) { const words = sel.anchorNode.nodeValue.substring(0, sel.anchorOffset); let index = words.lastIndexOf(":"); let lastWord = ""; if (index !== -1 && words.lastIndexOf(" ") < index) { lastWord = words.substring(index + 1, sel.anchorOffset); } else { const {text} = EmojiComposerExtension._getTextUntilSpace(sel.anchorNode, sel.anchorOffset); index = text.lastIndexOf(":"); if (index !== -1 && text.lastIndexOf(" ") < index) { lastWord = text.substring(index + 1); } else { return {triggerWord: "", emojiOptions: []}; } } if (lastWord.length > 0) { return {triggerWord: lastWord, emojiOptions: EmojiComposerExtension._findMatches(lastWord)}; } return {triggerWord: lastWord, emojiOptions: []}; } return {triggerWord: "", emojiOptions: []}; } static _onSelectEmoji = ({editor, actionArg}) => { const {emojiName, replaceSelection} = actionArg; if (!emojiName) return null; if (replaceSelection) { const sel = editor.currentSelection(); if (sel.anchorNode && sel.anchorNode.nodeValue && sel.anchorNode.nodeValue.length > 0 && sel.isCollapsed) { const words = sel.anchorNode.nodeValue.substring(0, sel.anchorOffset); let index = words.lastIndexOf(":"); let lastWord = words.substring(index + 1, sel.anchorOffset); if (index !== -1 && words.lastIndexOf(" ") < index) { editor.select(sel.anchorNode, sel.anchorOffset - lastWord.length - 1, sel.focusNode, sel.focusOffset); } else { const {text, textNode} = EmojiComposerExtension._getTextUntilSpace(sel.anchorNode, sel.anchorOffset); index = text.lastIndexOf(":"); lastWord = text.substring(index + 1); const offset = textNode.nodeValue.lastIndexOf(":"); editor.select(textNode, offset, sel.focusNode, sel.focusOffset); editor.delete(); } } } const emojiChar = emoji.get(emojiName); const html = ``; editor.insertHTML(html, {selectInsertion: false}); EmojiActions.useEmoji({emojiName: emojiName, emojiChar: emojiChar}); return null; }; static _emojiPickerWidth(emojiOptions) { let maxLength = 0; for (const emojiOption of emojiOptions) { if (emojiOption.length > maxLength) { maxLength = emojiOption.length; } } // TODO: Calculate width of words more accurately for a closer fit. const WIDTH_PER_CHAR = 8; return (maxLength + 10) * WIDTH_PER_CHAR; } static _emojiPickerHeight(emojiOptions) { const HEIGHT_PER_EMOJI = 25; if (emojiOptions.length < 5) { return emojiOptions.length * HEIGHT_PER_EMOJI + 20; } return 5 * HEIGHT_PER_EMOJI + 23; } static _getTextUntilSpace(node, offset) { let text = node.nodeValue.substring(0, offset); let prevTextNode = DOMUtils.previousTextNode(node); if (!prevTextNode) return {text: text, textNode: node}; while (prevTextNode) { if (prevTextNode.nodeValue.indexOf(" ") === -1 && prevTextNode.nodeValue.indexOf(":") === -1) { text = prevTextNode.nodeValue + text; prevTextNode = DOMUtils.previousTextNode(prevTextNode); } else if (prevTextNode.nextSibling && prevTextNode.nextSibling.nodeName !== "DIV") { text = prevTextNode.nodeValue.trim() + text; break; } else { break; } } return {text: text, textNode: prevTextNode}; } static _findMatches(word) { const emojiOptions = [] const emojiNames = Object.keys(emoji.emoji).sort(); for (const emojiName of emojiNames) { if (word === emojiName.substring(0, word.length)) { emojiOptions.push(emojiName); } } return emojiOptions; } } export default EmojiComposerExtension; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-data.json ================================================ {"emojiData":[{"name":"COPYRIGHT SIGN","unified":"00A9","variations":["00A9-FE0F"],"docomo":"E731","au":"E558","softbank":"E24E","google":"FEB29","image":"00a9.png","sheet_x":0,"sheet_y":0,"short_name":"copyright","short_names":["copyright"],"text":null,"texts":null,"category":"Symbols","sort_order":197,"has_img_apple":true,"has_img_google":true,"has_img_twitter":false,"has_img_emojione":true},{"name":"REGISTERED SIGN","unified":"00AE","variations":["00AE-FE0F"],"docomo":"E736","au":"E559","softbank":"E24F","google":"FEB2D","image":"00ae.png","sheet_x":0,"sheet_y":1,"short_name":"registered","short_names":["registered"],"text":null,"texts":null,"category":"Symbols","sort_order":198,"has_img_apple":true,"has_img_google":true,"has_img_twitter":false,"has_img_emojione":true},{"name":"DOUBLE EXCLAMATION MARK","unified":"203C","variations":["203C-FE0F"],"docomo":"E704","au":"EB30","softbank":null,"google":"FEB06","image":"203c.png","sheet_x":0,"sheet_y":2,"short_name":"bangbang","short_names":["bangbang"],"text":null,"texts":null,"category":"Symbols","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EXCLAMATION QUESTION MARK","unified":"2049","variations":["2049-FE0F"],"docomo":"E703","au":"EB2F","softbank":null,"google":"FEB05","image":"2049.png","sheet_x":0,"sheet_y":3,"short_name":"interrobang","short_names":["interrobang"],"text":null,"texts":null,"category":"Symbols","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRADE MARK SIGN","unified":"2122","variations":["2122-FE0F"],"docomo":"E732","au":"E54E","softbank":"E537","google":"FEB2A","image":"2122.png","sheet_x":0,"sheet_y":4,"short_name":"tm","short_names":["tm"],"text":null,"texts":null,"category":"Symbols","sort_order":199,"has_img_apple":true,"has_img_google":true,"has_img_twitter":false,"has_img_emojione":true},{"name":"INFORMATION SOURCE","unified":"2139","variations":["2139-FE0F"],"docomo":null,"au":"E533","softbank":null,"google":"FEB47","image":"2139.png","sheet_x":0,"sheet_y":5,"short_name":"information_source","short_names":["information_source"],"text":null,"texts":null,"category":"Symbols","sort_order":180,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFT RIGHT ARROW","unified":"2194","variations":["2194-FE0F"],"docomo":"E73C","au":"EB7A","softbank":null,"google":"FEAF6","image":"2194.png","sheet_x":0,"sheet_y":6,"short_name":"left_right_arrow","short_names":["left_right_arrow"],"text":null,"texts":null,"category":"Symbols","sort_order":172,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UP DOWN ARROW","unified":"2195","variations":["2195-FE0F"],"docomo":"E73D","au":"EB7B","softbank":null,"google":"FEAF7","image":"2195.png","sheet_x":0,"sheet_y":7,"short_name":"arrow_up_down","short_names":["arrow_up_down"],"text":null,"texts":null,"category":"Symbols","sort_order":171,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NORTH WEST ARROW","unified":"2196","variations":["2196-FE0F"],"docomo":"E697","au":"E54C","softbank":"E237","google":"FEAF2","image":"2196.png","sheet_x":0,"sheet_y":8,"short_name":"arrow_upper_left","short_names":["arrow_upper_left"],"text":null,"texts":null,"category":"Symbols","sort_order":170,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NORTH EAST ARROW","unified":"2197","variations":["2197-FE0F"],"docomo":"E678","au":"E555","softbank":"E236","google":"FEAF0","image":"2197.png","sheet_x":0,"sheet_y":9,"short_name":"arrow_upper_right","short_names":["arrow_upper_right"],"text":null,"texts":null,"category":"Symbols","sort_order":167,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SOUTH EAST ARROW","unified":"2198","variations":["2198-FE0F"],"docomo":"E696","au":"E54D","softbank":"E238","google":"FEAF1","image":"2198.png","sheet_x":0,"sheet_y":10,"short_name":"arrow_lower_right","short_names":["arrow_lower_right"],"text":null,"texts":null,"category":"Symbols","sort_order":168,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SOUTH WEST ARROW","unified":"2199","variations":["2199-FE0F"],"docomo":"E6A5","au":"E556","softbank":"E239","google":"FEAF3","image":"2199.png","sheet_x":0,"sheet_y":11,"short_name":"arrow_lower_left","short_names":["arrow_lower_left"],"text":null,"texts":null,"category":"Symbols","sort_order":169,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFTWARDS ARROW WITH HOOK","unified":"21A9","variations":["21A9-FE0F"],"docomo":"E6DA","au":"E55D","softbank":null,"google":"FEB83","image":"21a9.png","sheet_x":0,"sheet_y":12,"short_name":"leftwards_arrow_with_hook","short_names":["leftwards_arrow_with_hook"],"text":null,"texts":null,"category":"Symbols","sort_order":175,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RIGHTWARDS ARROW WITH HOOK","unified":"21AA","variations":["21AA-FE0F"],"docomo":null,"au":"E55C","softbank":null,"google":"FEB88","image":"21aa.png","sheet_x":0,"sheet_y":13,"short_name":"arrow_right_hook","short_names":["arrow_right_hook"],"text":null,"texts":null,"category":"Symbols","sort_order":174,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WATCH","unified":"231A","variations":["231A-FE0F"],"docomo":"E71F","au":"E57A","softbank":null,"google":"FE01D","image":"231a.png","sheet_x":0,"sheet_y":14,"short_name":"watch","short_names":["watch"],"text":null,"texts":null,"category":"Objects","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOURGLASS","unified":"231B","variations":["231B-FE0F"],"docomo":"E71C","au":"E57B","softbank":null,"google":"FE01C","image":"231b.png","sheet_x":0,"sheet_y":15,"short_name":"hourglass","short_names":["hourglass"],"text":null,"texts":null,"category":"Objects","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYBOARD","unified":"2328","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2328.png","sheet_x":0,"sheet_y":16,"short_name":"keyboard","short_names":["keyboard"],"text":null,"texts":null,"category":"Objects","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK RIGHT-POINTING DOUBLE TRIANGLE","unified":"23E9","variations":[],"docomo":null,"au":"E530","softbank":"E23C","google":"FEAFE","image":"23e9.png","sheet_x":0,"sheet_y":17,"short_name":"fast_forward","short_names":["fast_forward"],"text":null,"texts":null,"category":"Symbols","sort_order":153,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK LEFT-POINTING DOUBLE TRIANGLE","unified":"23EA","variations":[],"docomo":null,"au":"E52F","softbank":"E23D","google":"FEAFF","image":"23ea.png","sheet_x":0,"sheet_y":18,"short_name":"rewind","short_names":["rewind"],"text":null,"texts":null,"category":"Symbols","sort_order":154,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK UP-POINTING DOUBLE TRIANGLE","unified":"23EB","variations":[],"docomo":null,"au":"E545","softbank":null,"google":"FEB03","image":"23eb.png","sheet_x":0,"sheet_y":19,"short_name":"arrow_double_up","short_names":["arrow_double_up"],"text":null,"texts":null,"category":"Symbols","sort_order":161,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK DOWN-POINTING DOUBLE TRIANGLE","unified":"23EC","variations":[],"docomo":null,"au":"E544","softbank":null,"google":"FEB02","image":"23ec.png","sheet_x":0,"sheet_y":20,"short_name":"arrow_double_down","short_names":["arrow_double_down"],"text":null,"texts":null,"category":"Symbols","sort_order":162,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR","unified":"23ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23ed.png","sheet_x":0,"sheet_y":21,"short_name":"black_right_pointing_double_triangle_with_vertical_bar","short_names":["black_right_pointing_double_triangle_with_vertical_bar"],"text":null,"texts":null,"category":"Symbols","sort_order":151,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR","unified":"23EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23ee.png","sheet_x":0,"sheet_y":22,"short_name":"black_left_pointing_double_triangle_with_vertical_bar","short_names":["black_left_pointing_double_triangle_with_vertical_bar"],"text":null,"texts":null,"category":"Symbols","sort_order":152,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR","unified":"23EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23ef.png","sheet_x":0,"sheet_y":23,"short_name":"black_right_pointing_triangle_with_double_vertical_bar","short_names":["black_right_pointing_triangle_with_double_vertical_bar"],"text":null,"texts":null,"category":"Symbols","sort_order":148,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ALARM CLOCK","unified":"23F0","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02D","google":"FE02A","image":"23f0.png","sheet_x":0,"sheet_y":24,"short_name":"alarm_clock","short_names":["alarm_clock"],"text":null,"texts":null,"category":"Objects","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STOPWATCH","unified":"23F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23f1.png","sheet_x":0,"sheet_y":25,"short_name":"stopwatch","short_names":["stopwatch"],"text":null,"texts":null,"category":"Objects","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TIMER CLOCK","unified":"23F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23f2.png","sheet_x":0,"sheet_y":26,"short_name":"timer_clock","short_names":["timer_clock"],"text":null,"texts":null,"category":"Objects","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOURGLASS WITH FLOWING SAND","unified":"23F3","variations":[],"docomo":"E71C","au":"E47C","softbank":null,"google":"FE01B","image":"23f3.png","sheet_x":0,"sheet_y":27,"short_name":"hourglass_flowing_sand","short_names":["hourglass_flowing_sand"],"text":null,"texts":null,"category":"Objects","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOUBLE VERTICAL BAR","unified":"23F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23f8.png","sheet_x":0,"sheet_y":28,"short_name":"double_vertical_bar","short_names":["double_vertical_bar"],"text":null,"texts":null,"category":"Symbols","sort_order":147,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SQUARE FOR STOP","unified":"23F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23f9.png","sheet_x":0,"sheet_y":29,"short_name":"black_square_for_stop","short_names":["black_square_for_stop"],"text":null,"texts":null,"category":"Symbols","sort_order":149,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK CIRCLE FOR RECORD","unified":"23FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"23fa.png","sheet_x":0,"sheet_y":30,"short_name":"black_circle_for_record","short_names":["black_circle_for_record"],"text":null,"texts":null,"category":"Symbols","sort_order":150,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCLED LATIN CAPITAL LETTER M","unified":"24C2","variations":["24C2-FE0F"],"docomo":"E65C","au":"E5BC","softbank":"E434","google":"FE7E1","image":"24c2.png","sheet_x":0,"sheet_y":31,"short_name":"m","short_names":["m"],"text":null,"texts":null,"category":"Symbols","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SMALL SQUARE","unified":"25AA","variations":["25AA-FE0F"],"docomo":null,"au":"E532","softbank":"E21A","google":"FEB6E","image":"25aa.png","sheet_x":0,"sheet_y":32,"short_name":"black_small_square","short_names":["black_small_square"],"text":null,"texts":null,"category":"Symbols","sort_order":216,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SMALL SQUARE","unified":"25AB","variations":["25AB-FE0F"],"docomo":null,"au":"E531","softbank":"E21B","google":"FEB6D","image":"25ab.png","sheet_x":0,"sheet_y":33,"short_name":"white_small_square","short_names":["white_small_square"],"text":null,"texts":null,"category":"Symbols","sort_order":217,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK RIGHT-POINTING TRIANGLE","unified":"25B6","variations":["25B6-FE0F"],"docomo":null,"au":"E52E","softbank":"E23A","google":"FEAFC","image":"25b6.png","sheet_x":0,"sheet_y":34,"short_name":"arrow_forward","short_names":["arrow_forward"],"text":null,"texts":null,"category":"Symbols","sort_order":146,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK LEFT-POINTING TRIANGLE","unified":"25C0","variations":["25C0-FE0F"],"docomo":null,"au":"E52D","softbank":"E23B","google":"FEAFD","image":"25c0.png","sheet_x":0,"sheet_y":35,"short_name":"arrow_backward","short_names":["arrow_backward"],"text":null,"texts":null,"category":"Symbols","sort_order":158,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE MEDIUM SQUARE","unified":"25FB","variations":["25FB-FE0F"],"docomo":null,"au":"E538","softbank":"E21B","google":"FEB71","image":"25fb.png","sheet_x":0,"sheet_y":36,"short_name":"white_medium_square","short_names":["white_medium_square"],"text":null,"texts":null,"category":"Symbols","sort_order":222,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK MEDIUM SQUARE","unified":"25FC","variations":["25FC-FE0F"],"docomo":null,"au":"E539","softbank":"E21A","google":"FEB72","image":"25fc.png","sheet_x":0,"sheet_y":37,"short_name":"black_medium_square","short_names":["black_medium_square"],"text":null,"texts":null,"category":"Symbols","sort_order":221,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE MEDIUM SMALL SQUARE","unified":"25FD","variations":["25FD-FE0F"],"docomo":null,"au":"E534","softbank":"E21B","google":"FEB6F","image":"25fd.png","sheet_x":0,"sheet_y":38,"short_name":"white_medium_small_square","short_names":["white_medium_small_square"],"text":null,"texts":null,"category":"Symbols","sort_order":224,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK MEDIUM SMALL SQUARE","unified":"25FE","variations":["25FE-FE0F"],"docomo":null,"au":"E535","softbank":"E21A","google":"FEB70","image":"25fe.png","sheet_x":0,"sheet_y":39,"short_name":"black_medium_small_square","short_names":["black_medium_small_square"],"text":null,"texts":null,"category":"Symbols","sort_order":223,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SUN WITH RAYS","unified":"2600","variations":["2600-FE0F"],"docomo":"E63E","au":"E488","softbank":"E04A","google":"FE000","image":"2600.png","sheet_x":0,"sheet_y":40,"short_name":"sunny","short_names":["sunny"],"text":null,"texts":null,"category":"Nature","sort_order":123,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOUD","unified":"2601","variations":["2601-FE0F"],"docomo":"E63F","au":"E48D","softbank":"E049","google":"FE001","image":"2601.png","sheet_x":1,"sheet_y":0,"short_name":"cloud","short_names":["cloud"],"text":null,"texts":null,"category":"Nature","sort_order":128,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UMBRELLA","unified":"2602","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2602.png","sheet_x":1,"sheet_y":1,"short_name":"umbrella","short_names":["umbrella"],"text":null,"texts":null,"category":"Nature","sort_order":143,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNOWMAN","unified":"2603","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2603.png","sheet_x":1,"sheet_y":2,"short_name":"showman","short_names":["showman"],"text":null,"texts":null,"category":"Nature","sort_order":137,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COMET","unified":"2604","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2604.png","sheet_x":1,"sheet_y":3,"short_name":"comet","short_names":["comet"],"text":null,"texts":null,"category":"Nature","sort_order":122,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK TELEPHONE","unified":"260E","variations":["260E-FE0F"],"docomo":"E687","au":"E596","softbank":"E009","google":"FE523","image":"260e.png","sheet_x":1,"sheet_y":4,"short_name":"phone","short_names":["phone","telephone"],"text":null,"texts":null,"category":"Objects","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BALLOT BOX WITH CHECK","unified":"2611","variations":["2611-FE0F"],"docomo":null,"au":"EB02","softbank":null,"google":"FEB8B","image":"2611.png","sheet_x":1,"sheet_y":5,"short_name":"ballot_box_with_check","short_names":["ballot_box_with_check"],"text":null,"texts":null,"category":"Symbols","sort_order":205,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UMBRELLA WITH RAIN DROPS","unified":"2614","variations":["2614-FE0F"],"docomo":"E640","au":"E48C","softbank":"E04B","google":"FE002","image":"2614.png","sheet_x":1,"sheet_y":6,"short_name":"umbrella","short_names":["umbrella"],"text":null,"texts":null,"category":"Nature","sort_order":144,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOT BEVERAGE","unified":"2615","variations":["2615-FE0F"],"docomo":"E670","au":"E597","softbank":"E045","google":"FE981","image":"2615.png","sheet_x":1,"sheet_y":7,"short_name":"coffee","short_names":["coffee"],"text":null,"texts":null,"category":"Foods","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHAMROCK","unified":"2618","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2618.png","sheet_x":1,"sheet_y":8,"short_name":"shamrock","short_names":["shamrock"],"text":null,"texts":null,"category":"Nature","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE UP POINTING INDEX","unified":"261D","variations":["261D-FE0F"],"docomo":null,"au":"E4F6","softbank":"E00F","google":"FEB98","image":"261d.png","sheet_x":1,"sheet_y":9,"short_name":"point_up","short_names":["point_up"],"text":null,"texts":null,"category":"People","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"261D-1F3FB":{"unified":"261D-1F3FB","image":"261d-1f3fb.png","sheet_x":1,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"261D-1F3FC":{"unified":"261D-1F3FC","image":"261d-1f3fc.png","sheet_x":1,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"261D-1F3FD":{"unified":"261D-1F3FD","image":"261d-1f3fd.png","sheet_x":1,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"261D-1F3FE":{"unified":"261D-1F3FE","image":"261d-1f3fe.png","sheet_x":1,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"261D-1F3FF":{"unified":"261D-1F3FF","image":"261d-1f3ff.png","sheet_x":1,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"SKULL AND CROSSBONES","unified":"2620","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2620.png","sheet_x":1,"sheet_y":15,"short_name":"skull_and_crossbones","short_names":["skull_and_crossbones"],"text":null,"texts":null,"category":"Objects","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RADIOACTIVE SIGN","unified":"2622","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2622.png","sheet_x":1,"sheet_y":16,"short_name":"radioactive_sign","short_names":["radioactive_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BIOHAZARD SIGN","unified":"2623","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2623.png","sheet_x":1,"sheet_y":17,"short_name":"biohazard_sign","short_names":["biohazard_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ORTHODOX CROSS","unified":"2626","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2626.png","sheet_x":1,"sheet_y":18,"short_name":"orthodox_cross","short_names":["orthodox_cross"],"text":null,"texts":null,"category":"Symbols","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STAR AND CRESCENT","unified":"262A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"262a.png","sheet_x":1,"sheet_y":19,"short_name":"star_and_crescent","short_names":["star_and_crescent"],"text":null,"texts":null,"category":"Symbols","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PEACE SYMBOL","unified":"262E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"262e.png","sheet_x":1,"sheet_y":20,"short_name":"peace_symbol","short_names":["peace_symbol"],"text":null,"texts":null,"category":"Symbols","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"YIN YANG","unified":"262F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"262f.png","sheet_x":1,"sheet_y":21,"short_name":"yin_yang","short_names":["yin_yang"],"text":null,"texts":null,"category":"Symbols","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHEEL OF DHARMA","unified":"2638","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2638.png","sheet_x":1,"sheet_y":22,"short_name":"wheel_of_dharma","short_names":["wheel_of_dharma"],"text":null,"texts":null,"category":"Symbols","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE FROWNING FACE","unified":"2639","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2639.png","sheet_x":1,"sheet_y":23,"short_name":"white_frowning_face","short_names":["white_frowning_face"],"text":null,"texts":null,"category":"People","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SMILING FACE","unified":"263A","variations":["263A-FE0F"],"docomo":"E6F0","au":"E4FB","softbank":"E414","google":"FE336","image":"263a.png","sheet_x":1,"sheet_y":24,"short_name":"relaxed","short_names":["relaxed"],"text":null,"texts":null,"category":"People","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ARIES","unified":"2648","variations":["2648-FE0F"],"docomo":"E646","au":"E48F","softbank":"E23F","google":"FE02B","image":"2648.png","sheet_x":1,"sheet_y":25,"short_name":"aries","short_names":["aries"],"text":null,"texts":null,"category":"Symbols","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TAURUS","unified":"2649","variations":["2649-FE0F"],"docomo":"E647","au":"E490","softbank":"E240","google":"FE02C","image":"2649.png","sheet_x":1,"sheet_y":26,"short_name":"taurus","short_names":["taurus"],"text":null,"texts":null,"category":"Symbols","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GEMINI","unified":"264A","variations":["264A-FE0F"],"docomo":"E648","au":"E491","softbank":"E241","google":"FE02D","image":"264a.png","sheet_x":1,"sheet_y":27,"short_name":"gemini","short_names":["gemini"],"text":null,"texts":null,"category":"Symbols","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CANCER","unified":"264B","variations":["264B-FE0F"],"docomo":"E649","au":"E492","softbank":"E242","google":"FE02E","image":"264b.png","sheet_x":1,"sheet_y":28,"short_name":"cancer","short_names":["cancer"],"text":null,"texts":null,"category":"Symbols","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEO","unified":"264C","variations":["264C-FE0F"],"docomo":"E64A","au":"E493","softbank":"E243","google":"FE02F","image":"264c.png","sheet_x":1,"sheet_y":29,"short_name":"leo","short_names":["leo"],"text":null,"texts":null,"category":"Symbols","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIRGO","unified":"264D","variations":["264D-FE0F"],"docomo":"E64B","au":"E494","softbank":"E244","google":"FE030","image":"264d.png","sheet_x":1,"sheet_y":30,"short_name":"virgo","short_names":["virgo"],"text":null,"texts":null,"category":"Symbols","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LIBRA","unified":"264E","variations":["264E-FE0F"],"docomo":"E64C","au":"E495","softbank":"E245","google":"FE031","image":"264e.png","sheet_x":1,"sheet_y":31,"short_name":"libra","short_names":["libra"],"text":null,"texts":null,"category":"Symbols","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCORPIUS","unified":"264F","variations":["264F-FE0F"],"docomo":"E64D","au":"E496","softbank":"E246","google":"FE032","image":"264f.png","sheet_x":1,"sheet_y":32,"short_name":"scorpius","short_names":["scorpius"],"text":null,"texts":null,"category":"Symbols","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SAGITTARIUS","unified":"2650","variations":["2650-FE0F"],"docomo":"E64E","au":"E497","softbank":"E247","google":"FE033","image":"2650.png","sheet_x":1,"sheet_y":33,"short_name":"sagittarius","short_names":["sagittarius"],"text":null,"texts":null,"category":"Symbols","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAPRICORN","unified":"2651","variations":["2651-FE0F"],"docomo":"E64F","au":"E498","softbank":"E248","google":"FE034","image":"2651.png","sheet_x":1,"sheet_y":34,"short_name":"capricorn","short_names":["capricorn"],"text":null,"texts":null,"category":"Symbols","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AQUARIUS","unified":"2652","variations":["2652-FE0F"],"docomo":"E650","au":"E499","softbank":"E249","google":"FE035","image":"2652.png","sheet_x":1,"sheet_y":35,"short_name":"aquarius","short_names":["aquarius"],"text":null,"texts":null,"category":"Symbols","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PISCES","unified":"2653","variations":["2653-FE0F"],"docomo":"E651","au":"E49A","softbank":"E24A","google":"FE036","image":"2653.png","sheet_x":1,"sheet_y":36,"short_name":"pisces","short_names":["pisces"],"text":null,"texts":null,"category":"Symbols","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SPADE SUIT","unified":"2660","variations":["2660-FE0F"],"docomo":"E68E","au":"E5A1","softbank":"E20E","google":"FEB1B","image":"2660.png","sheet_x":1,"sheet_y":37,"short_name":"spades","short_names":["spades"],"text":null,"texts":null,"category":"Symbols","sort_order":237,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK CLUB SUIT","unified":"2663","variations":["2663-FE0F"],"docomo":"E690","au":"E5A3","softbank":"E20F","google":"FEB1D","image":"2663.png","sheet_x":1,"sheet_y":38,"short_name":"clubs","short_names":["clubs"],"text":null,"texts":null,"category":"Symbols","sort_order":238,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK HEART SUIT","unified":"2665","variations":["2665-FE0F"],"docomo":"E68D","au":"EAA5","softbank":"E20C","google":"FEB1A","image":"2665.png","sheet_x":1,"sheet_y":39,"short_name":"hearts","short_names":["hearts"],"text":null,"texts":null,"category":"Symbols","sort_order":239,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK DIAMOND SUIT","unified":"2666","variations":["2666-FE0F"],"docomo":"E68F","au":"E5A2","softbank":"E20D","google":"FEB1C","image":"2666.png","sheet_x":1,"sheet_y":40,"short_name":"diamonds","short_names":["diamonds"],"text":null,"texts":null,"category":"Symbols","sort_order":240,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOT SPRINGS","unified":"2668","variations":["2668-FE0F"],"docomo":"E6F7","au":"E4BC","softbank":"E123","google":"FE7FA","image":"2668.png","sheet_x":2,"sheet_y":0,"short_name":"hotsprings","short_names":["hotsprings"],"text":null,"texts":null,"category":"Symbols","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK UNIVERSAL RECYCLING SYMBOL","unified":"267B","variations":["267B-FE0F"],"docomo":"E735","au":"EB79","softbank":null,"google":"FEB2C","image":"267b.png","sheet_x":2,"sheet_y":1,"short_name":"recycle","short_names":["recycle"],"text":null,"texts":null,"category":"Symbols","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHEELCHAIR SYMBOL","unified":"267F","variations":["267F-FE0F"],"docomo":"E69B","au":"E47F","softbank":"E20A","google":"FEB20","image":"267f.png","sheet_x":2,"sheet_y":2,"short_name":"wheelchair","short_names":["wheelchair"],"text":null,"texts":null,"category":"Symbols","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAMMER AND PICK","unified":"2692","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2692.png","sheet_x":2,"sheet_y":3,"short_name":"hammer_and_pick","short_names":["hammer_and_pick"],"text":null,"texts":null,"category":"Objects","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANCHOR","unified":"2693","variations":["2693-FE0F"],"docomo":"E661","au":"E4A9","softbank":"E202","google":"FE4C1","image":"2693.png","sheet_x":2,"sheet_y":4,"short_name":"anchor","short_names":["anchor"],"text":null,"texts":null,"category":"Places","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CROSSED SWORDS","unified":"2694","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2694.png","sheet_x":2,"sheet_y":5,"short_name":"crossed_swords","short_names":["crossed_swords"],"text":null,"texts":null,"category":"Objects","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCALES","unified":"2696","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2696.png","sheet_x":2,"sheet_y":6,"short_name":"scales","short_names":["scales"],"text":null,"texts":null,"category":"Objects","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ALEMBIC","unified":"2697","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2697.png","sheet_x":2,"sheet_y":7,"short_name":"alembic","short_names":["alembic"],"text":null,"texts":null,"category":"Objects","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GEAR","unified":"2699","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2699.png","sheet_x":2,"sheet_y":8,"short_name":"gear","short_names":["gear"],"text":null,"texts":null,"category":"Objects","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ATOM SYMBOL","unified":"269B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"269b.png","sheet_x":2,"sheet_y":9,"short_name":"atom_symbol","short_names":["atom_symbol"],"text":null,"texts":null,"category":"Symbols","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLEUR-DE-LIS","unified":"269C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"269c.png","sheet_x":2,"sheet_y":10,"short_name":"fleur_de_lis","short_names":["fleur_de_lis"],"text":null,"texts":null,"category":"Symbols","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WARNING SIGN","unified":"26A0","variations":["26A0-FE0F"],"docomo":"E737","au":"E481","softbank":"E252","google":"FEB23","image":"26a0.png","sheet_x":2,"sheet_y":11,"short_name":"warning","short_names":["warning"],"text":null,"texts":null,"category":"Symbols","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIGH VOLTAGE SIGN","unified":"26A1","variations":["26A1-FE0F"],"docomo":"E642","au":"E487","softbank":"E13D","google":"FE004","image":"26a1.png","sheet_x":2,"sheet_y":12,"short_name":"zap","short_names":["zap"],"text":null,"texts":null,"category":"Nature","sort_order":132,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MEDIUM WHITE CIRCLE","unified":"26AA","variations":["26AA-FE0F"],"docomo":"E69C","au":"E53A","softbank":"E219","google":"FEB65","image":"26aa.png","sheet_x":2,"sheet_y":13,"short_name":"white_circle","short_names":["white_circle"],"text":null,"texts":null,"category":"Symbols","sort_order":207,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MEDIUM BLACK CIRCLE","unified":"26AB","variations":["26AB-FE0F"],"docomo":"E69C","au":"E53B","softbank":"E219","google":"FEB66","image":"26ab.png","sheet_x":2,"sheet_y":14,"short_name":"black_circle","short_names":["black_circle"],"text":null,"texts":null,"category":"Symbols","sort_order":208,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COFFIN","unified":"26B0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26b0.png","sheet_x":2,"sheet_y":15,"short_name":"coffin","short_names":["coffin"],"text":null,"texts":null,"category":"Objects","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FUNERAL URN","unified":"26B1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26b1.png","sheet_x":2,"sheet_y":16,"short_name":"funeral_urn","short_names":["funeral_urn"],"text":null,"texts":null,"category":"Objects","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SOCCER BALL","unified":"26BD","variations":["26BD-FE0F"],"docomo":"E656","au":"E4B6","softbank":"E018","google":"FE7D4","image":"26bd.png","sheet_x":2,"sheet_y":17,"short_name":"soccer","short_names":["soccer"],"text":null,"texts":null,"category":"Activity","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BASEBALL","unified":"26BE","variations":["26BE-FE0F"],"docomo":"E653","au":"E4BA","softbank":"E016","google":"FE7D1","image":"26be.png","sheet_x":2,"sheet_y":18,"short_name":"baseball","short_names":["baseball"],"text":null,"texts":null,"category":"Activity","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNOWMAN WITHOUT SNOW","unified":"26C4","variations":["26C4-FE0F"],"docomo":"E641","au":"E485","softbank":"E048","google":"FE003","image":"26c4.png","sheet_x":2,"sheet_y":19,"short_name":"snowman","short_names":["snowman"],"text":null,"texts":null,"category":"Nature","sort_order":138,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUN BEHIND CLOUD","unified":"26C5","variations":["26C5-FE0F"],"docomo":"E63E-E63F","au":"E48E","softbank":"E04A-E049","google":"FE00F","image":"26c5.png","sheet_x":2,"sheet_y":20,"short_name":"partly_sunny","short_names":["partly_sunny"],"text":null,"texts":null,"category":"Nature","sort_order":125,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"THUNDER CLOUD AND RAIN","unified":"26C8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26c8.png","sheet_x":2,"sheet_y":21,"short_name":"thunder_cloud_and_rain","short_names":["thunder_cloud_and_rain"],"text":null,"texts":null,"category":"Nature","sort_order":130,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPHIUCHUS","unified":"26CE","variations":[],"docomo":null,"au":"E49B","softbank":"E24B","google":"FE037","image":"26ce.png","sheet_x":2,"sheet_y":22,"short_name":"ophiuchus","short_names":["ophiuchus"],"text":null,"texts":null,"category":"Symbols","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PICK","unified":"26CF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26cf.png","sheet_x":2,"sheet_y":23,"short_name":"pick","short_names":["pick"],"text":null,"texts":null,"category":"Objects","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HELMET WITH WHITE CROSS","unified":"26D1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26d1.png","sheet_x":2,"sheet_y":24,"short_name":"helmet_with_white_cross","short_names":["helmet_with_white_cross"],"text":null,"texts":null,"category":"People","sort_order":193,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHAINS","unified":"26D3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26d3.png","sheet_x":2,"sheet_y":25,"short_name":"chains","short_names":["chains"],"text":null,"texts":null,"category":"Objects","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO ENTRY","unified":"26D4","variations":["26D4-FE0F"],"docomo":"E72F","au":"E484","softbank":"E137","google":"FEB26","image":"26d4.png","sheet_x":2,"sheet_y":26,"short_name":"no_entry","short_names":["no_entry"],"text":null,"texts":null,"category":"Symbols","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHINTO SHRINE","unified":"26E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26e9.png","sheet_x":2,"sheet_y":27,"short_name":"shinto_shrine","short_names":["shinto_shrine"],"text":null,"texts":null,"category":"Places","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHURCH","unified":"26EA","variations":["26EA-FE0F"],"docomo":null,"au":"E5BB","softbank":"E037","google":"FE4BB","image":"26ea.png","sheet_x":2,"sheet_y":28,"short_name":"church","short_names":["church"],"text":null,"texts":null,"category":"Places","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUNTAIN","unified":"26F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f0.png","sheet_x":2,"sheet_y":29,"short_name":"mountain","short_names":["mountain"],"text":null,"texts":null,"category":"Places","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UMBRELLA ON GROUND","unified":"26F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f1.png","sheet_x":2,"sheet_y":30,"short_name":"umbrella_on_ground","short_names":["umbrella_on_ground"],"text":null,"texts":null,"category":"Objects","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FOUNTAIN","unified":"26F2","variations":["26F2-FE0F"],"docomo":null,"au":"E5CF","softbank":"E121","google":"FE4BC","image":"26f2.png","sheet_x":2,"sheet_y":31,"short_name":"fountain","short_names":["fountain"],"text":null,"texts":null,"category":"Places","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLAG IN HOLE","unified":"26F3","variations":["26F3-FE0F"],"docomo":"E654","au":"E599","softbank":"E014","google":"FE7D2","image":"26f3.png","sheet_x":2,"sheet_y":32,"short_name":"golf","short_names":["golf"],"text":null,"texts":null,"category":"Activity","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FERRY","unified":"26F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f4.png","sheet_x":2,"sheet_y":33,"short_name":"ferry","short_names":["ferry"],"text":null,"texts":null,"category":"Places","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SAILBOAT","unified":"26F5","variations":["26F5-FE0F"],"docomo":"E6A3","au":"E4B4","softbank":"E01C","google":"FE7EA","image":"26f5.png","sheet_x":2,"sheet_y":34,"short_name":"boat","short_names":["boat","sailboat"],"text":null,"texts":null,"category":"Places","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SKIER","unified":"26F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f7.png","sheet_x":2,"sheet_y":35,"short_name":"skier","short_names":["skier"],"text":null,"texts":null,"category":"Activity","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ICE SKATE","unified":"26F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f8.png","sheet_x":2,"sheet_y":36,"short_name":"ice_skate","short_names":["ice_skate"],"text":null,"texts":null,"category":"Activity","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PERSON WITH BALL","unified":"26F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"26f9.png","sheet_x":2,"sheet_y":37,"short_name":"person_with_ball","short_names":["person_with_ball"],"text":null,"texts":null,"category":"Activity","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"26F9-1F3FB":{"unified":"26F9-1F3FB","image":"26f9-1f3fb.png","sheet_x":2,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"26F9-1F3FC":{"unified":"26F9-1F3FC","image":"26f9-1f3fc.png","sheet_x":2,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"26F9-1F3FD":{"unified":"26F9-1F3FD","image":"26f9-1f3fd.png","sheet_x":2,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"26F9-1F3FE":{"unified":"26F9-1F3FE","image":"26f9-1f3fe.png","sheet_x":3,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"26F9-1F3FF":{"unified":"26F9-1F3FF","image":"26f9-1f3ff.png","sheet_x":3,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"TENT","unified":"26FA","variations":["26FA-FE0F"],"docomo":null,"au":"E5D0","softbank":"E122","google":"FE7FB","image":"26fa.png","sheet_x":3,"sheet_y":2,"short_name":"tent","short_names":["tent"],"text":null,"texts":null,"category":"Places","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FUEL PUMP","unified":"26FD","variations":["26FD-FE0F"],"docomo":"E66B","au":"E571","softbank":"E03A","google":"FE7F5","image":"26fd.png","sheet_x":3,"sheet_y":3,"short_name":"fuelpump","short_names":["fuelpump"],"text":null,"texts":null,"category":"Places","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SCISSORS","unified":"2702","variations":["2702-FE0F"],"docomo":"E675","au":"E516","softbank":"E313","google":"FE53E","image":"2702.png","sheet_x":3,"sheet_y":4,"short_name":"scissors","short_names":["scissors"],"text":null,"texts":null,"category":"Objects","sort_order":158,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE HEAVY CHECK MARK","unified":"2705","variations":[],"docomo":null,"au":"E55E","softbank":null,"google":"FEB4A","image":"2705.png","sheet_x":3,"sheet_y":5,"short_name":"white_check_mark","short_names":["white_check_mark"],"text":null,"texts":null,"category":"Symbols","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AIRPLANE","unified":"2708","variations":["2708-FE0F"],"docomo":"E662","au":"E4B3","softbank":"E01D","google":"FE7E9","image":"2708.png","sheet_x":3,"sheet_y":6,"short_name":"airplane","short_names":["airplane"],"text":null,"texts":null,"category":"Places","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ENVELOPE","unified":"2709","variations":["2709-FE0F"],"docomo":"E6D3","au":"E521","softbank":"E103","google":"FE529","image":"2709.png","sheet_x":3,"sheet_y":7,"short_name":"email","short_names":["email","envelope"],"text":null,"texts":null,"category":"Objects","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAISED FIST","unified":"270A","variations":[],"docomo":"E693","au":"EB83","softbank":"E010","google":"FEB93","image":"270a.png","sheet_x":3,"sheet_y":8,"short_name":"fist","short_names":["fist"],"text":null,"texts":null,"category":"People","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"270A-1F3FB":{"unified":"270A-1F3FB","image":"270a-1f3fb.png","sheet_x":3,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270A-1F3FC":{"unified":"270A-1F3FC","image":"270a-1f3fc.png","sheet_x":3,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270A-1F3FD":{"unified":"270A-1F3FD","image":"270a-1f3fd.png","sheet_x":3,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270A-1F3FE":{"unified":"270A-1F3FE","image":"270a-1f3fe.png","sheet_x":3,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270A-1F3FF":{"unified":"270A-1F3FF","image":"270a-1f3ff.png","sheet_x":3,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"RAISED HAND","unified":"270B","variations":[],"docomo":"E695","au":"E5A7","softbank":"E012","google":"FEB95","image":"270b.png","sheet_x":3,"sheet_y":14,"short_name":"hand","short_names":["hand","raised_hand"],"text":null,"texts":null,"category":"People","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"270B-1F3FB":{"unified":"270B-1F3FB","image":"270b-1f3fb.png","sheet_x":3,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270B-1F3FC":{"unified":"270B-1F3FC","image":"270b-1f3fc.png","sheet_x":3,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270B-1F3FD":{"unified":"270B-1F3FD","image":"270b-1f3fd.png","sheet_x":3,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270B-1F3FE":{"unified":"270B-1F3FE","image":"270b-1f3fe.png","sheet_x":3,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270B-1F3FF":{"unified":"270B-1F3FF","image":"270b-1f3ff.png","sheet_x":3,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"VICTORY HAND","unified":"270C","variations":["270C-FE0F"],"docomo":"E694","au":"E5A6","softbank":"E011","google":"FEB94","image":"270c.png","sheet_x":3,"sheet_y":20,"short_name":"v","short_names":["v"],"text":null,"texts":null,"category":"People","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"270C-1F3FB":{"unified":"270C-1F3FB","image":"270c-1f3fb.png","sheet_x":3,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270C-1F3FC":{"unified":"270C-1F3FC","image":"270c-1f3fc.png","sheet_x":3,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270C-1F3FD":{"unified":"270C-1F3FD","image":"270c-1f3fd.png","sheet_x":3,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270C-1F3FE":{"unified":"270C-1F3FE","image":"270c-1f3fe.png","sheet_x":3,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270C-1F3FF":{"unified":"270C-1F3FF","image":"270c-1f3ff.png","sheet_x":3,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WRITING HAND","unified":"270D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"270d.png","sheet_x":3,"sheet_y":26,"short_name":"writing_hand","short_names":["writing_hand"],"text":null,"texts":null,"category":"People","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"270D-1F3FB":{"unified":"270D-1F3FB","image":"270d-1f3fb.png","sheet_x":3,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270D-1F3FC":{"unified":"270D-1F3FC","image":"270d-1f3fc.png","sheet_x":3,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270D-1F3FD":{"unified":"270D-1F3FD","image":"270d-1f3fd.png","sheet_x":3,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270D-1F3FE":{"unified":"270D-1F3FE","image":"270d-1f3fe.png","sheet_x":3,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"270D-1F3FF":{"unified":"270D-1F3FF","image":"270d-1f3ff.png","sheet_x":3,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PENCIL","unified":"270F","variations":["270F-FE0F"],"docomo":"E719","au":"E4A1","softbank":"E301","google":"FE539","image":"270f.png","sheet_x":3,"sheet_y":32,"short_name":"pencil2","short_names":["pencil2"],"text":null,"texts":null,"category":"Objects","sort_order":174,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK NIB","unified":"2712","variations":["2712-FE0F"],"docomo":"E6AE","au":"EB03","softbank":null,"google":"FE536","image":"2712.png","sheet_x":3,"sheet_y":33,"short_name":"black_nib","short_names":["black_nib"],"text":null,"texts":null,"category":"Objects","sort_order":172,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY CHECK MARK","unified":"2714","variations":["2714-FE0F"],"docomo":null,"au":"E557","softbank":null,"google":"FEB49","image":"2714.png","sheet_x":3,"sheet_y":34,"short_name":"heavy_check_mark","short_names":["heavy_check_mark"],"text":null,"texts":null,"category":"Symbols","sort_order":189,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY MULTIPLICATION X","unified":"2716","variations":["2716-FE0F"],"docomo":null,"au":"E54F","softbank":"E333","google":"FEB53","image":"2716.png","sheet_x":3,"sheet_y":35,"short_name":"heavy_multiplication_x","short_names":["heavy_multiplication_x"],"text":null,"texts":null,"category":"Symbols","sort_order":194,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LATIN CROSS","unified":"271D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"271d.png","sheet_x":3,"sheet_y":36,"short_name":"latin_cross","short_names":["latin_cross"],"text":null,"texts":null,"category":"Symbols","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STAR OF DAVID","unified":"2721","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2721.png","sheet_x":3,"sheet_y":37,"short_name":"star_of_david","short_names":["star_of_david"],"text":null,"texts":null,"category":"Symbols","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPARKLES","unified":"2728","variations":[],"docomo":"E6FA","au":"EAAB","softbank":"E32E","google":"FEB60","image":"2728.png","sheet_x":3,"sheet_y":38,"short_name":"sparkles","short_names":["sparkles"],"text":null,"texts":null,"category":"Nature","sort_order":121,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EIGHT SPOKED ASTERISK","unified":"2733","variations":["2733-FE0F"],"docomo":"E6F8","au":"E53E","softbank":"E206","google":"FEB62","image":"2733.png","sheet_x":3,"sheet_y":39,"short_name":"eight_spoked_asterisk","short_names":["eight_spoked_asterisk"],"text":null,"texts":null,"category":"Symbols","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EIGHT POINTED BLACK STAR","unified":"2734","variations":["2734-FE0F"],"docomo":"E6F8","au":"E479","softbank":"E205","google":"FEB61","image":"2734.png","sheet_x":3,"sheet_y":40,"short_name":"eight_pointed_black_star","short_names":["eight_pointed_black_star"],"text":null,"texts":null,"category":"Symbols","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNOWFLAKE","unified":"2744","variations":["2744-FE0F"],"docomo":null,"au":"E48A","softbank":null,"google":"FE00E","image":"2744.png","sheet_x":4,"sheet_y":0,"short_name":"snowflake","short_names":["snowflake"],"text":null,"texts":null,"category":"Nature","sort_order":135,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPARKLE","unified":"2747","variations":["2747-FE0F"],"docomo":"E6FA","au":"E46C","softbank":"E32E","google":"FEB77","image":"2747.png","sheet_x":4,"sheet_y":1,"short_name":"sparkle","short_names":["sparkle"],"text":null,"texts":null,"category":"Symbols","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CROSS MARK","unified":"274C","variations":[],"docomo":null,"au":"E550","softbank":"E333","google":"FEB45","image":"274c.png","sheet_x":4,"sheet_y":2,"short_name":"x","short_names":["x"],"text":null,"texts":null,"category":"Symbols","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED CROSS MARK","unified":"274E","variations":[],"docomo":null,"au":"E551","softbank":"E333","google":"FEB46","image":"274e.png","sheet_x":4,"sheet_y":3,"short_name":"negative_squared_cross_mark","short_names":["negative_squared_cross_mark"],"text":null,"texts":null,"category":"Symbols","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK QUESTION MARK ORNAMENT","unified":"2753","variations":[],"docomo":null,"au":"E483","softbank":"E020","google":"FEB09","image":"2753.png","sheet_x":4,"sheet_y":4,"short_name":"question","short_names":["question"],"text":null,"texts":null,"category":"Symbols","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE QUESTION MARK ORNAMENT","unified":"2754","variations":[],"docomo":null,"au":"E483","softbank":"E336","google":"FEB0A","image":"2754.png","sheet_x":4,"sheet_y":5,"short_name":"grey_question","short_names":["grey_question"],"text":null,"texts":null,"category":"Symbols","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE EXCLAMATION MARK ORNAMENT","unified":"2755","variations":[],"docomo":"E702","au":"E482","softbank":"E337","google":"FEB0B","image":"2755.png","sheet_x":4,"sheet_y":6,"short_name":"grey_exclamation","short_names":["grey_exclamation"],"text":null,"texts":null,"category":"Symbols","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY EXCLAMATION MARK SYMBOL","unified":"2757","variations":["2757-FE0F"],"docomo":"E702","au":"E482","softbank":"E021","google":"FEB04","image":"2757.png","sheet_x":4,"sheet_y":7,"short_name":"exclamation","short_names":["exclamation","heavy_exclamation_mark"],"text":null,"texts":null,"category":"Symbols","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY HEART EXCLAMATION MARK ORNAMENT","unified":"2763","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"2763.png","sheet_x":4,"sheet_y":8,"short_name":"heavy_heart_exclamation_mark_ornament","short_names":["heavy_heart_exclamation_mark_ornament"],"text":null,"texts":null,"category":"Symbols","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY BLACK HEART","unified":"2764","variations":["2764-FE0F"],"docomo":"E6EC","au":"E595","softbank":"E022","google":"FEB0C","image":"2764.png","sheet_x":4,"sheet_y":9,"short_name":"heart","short_names":["heart"],"text":"<3","texts":["<3"],"category":"Symbols","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY PLUS SIGN","unified":"2795","variations":[],"docomo":null,"au":"E53C","softbank":null,"google":"FEB51","image":"2795.png","sheet_x":4,"sheet_y":10,"short_name":"heavy_plus_sign","short_names":["heavy_plus_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":191,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY MINUS SIGN","unified":"2796","variations":[],"docomo":null,"au":"E53D","softbank":null,"google":"FEB52","image":"2796.png","sheet_x":4,"sheet_y":11,"short_name":"heavy_minus_sign","short_names":["heavy_minus_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":192,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY DIVISION SIGN","unified":"2797","variations":[],"docomo":null,"au":"E554","softbank":null,"google":"FEB54","image":"2797.png","sheet_x":4,"sheet_y":12,"short_name":"heavy_division_sign","short_names":["heavy_division_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":193,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK RIGHTWARDS ARROW","unified":"27A1","variations":["27A1-FE0F"],"docomo":null,"au":"E552","softbank":"E234","google":"FEAFA","image":"27a1.png","sheet_x":4,"sheet_y":13,"short_name":"arrow_right","short_names":["arrow_right"],"text":null,"texts":null,"category":"Symbols","sort_order":163,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CURLY LOOP","unified":"27B0","variations":[],"docomo":"E70A","au":"EB31","softbank":null,"google":"FEB08","image":"27b0.png","sheet_x":4,"sheet_y":14,"short_name":"curly_loop","short_names":["curly_loop"],"text":null,"texts":null,"category":"Symbols","sort_order":188,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOUBLE CURLY LOOP","unified":"27BF","variations":[],"docomo":"E6DF","au":null,"softbank":"E211","google":"FE82B","image":"27bf.png","sheet_x":4,"sheet_y":15,"short_name":"loop","short_names":["loop"],"text":null,"texts":null,"category":"Symbols","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS","unified":"2934","variations":["2934-FE0F"],"docomo":"E6F5","au":"EB2D","softbank":"E236","google":"FEAF4","image":"2934.png","sheet_x":4,"sheet_y":16,"short_name":"arrow_heading_up","short_names":["arrow_heading_up"],"text":null,"texts":null,"category":"Symbols","sort_order":176,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS","unified":"2935","variations":["2935-FE0F"],"docomo":"E700","au":"EB2E","softbank":"E238","google":"FEAF5","image":"2935.png","sheet_x":4,"sheet_y":17,"short_name":"arrow_heading_down","short_names":["arrow_heading_down"],"text":null,"texts":null,"category":"Symbols","sort_order":177,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFTWARDS BLACK ARROW","unified":"2B05","variations":["2B05-FE0F"],"docomo":null,"au":"E553","softbank":"E235","google":"FEAFB","image":"2b05.png","sheet_x":4,"sheet_y":18,"short_name":"arrow_left","short_names":["arrow_left"],"text":null,"texts":null,"category":"Symbols","sort_order":164,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UPWARDS BLACK ARROW","unified":"2B06","variations":["2B06-FE0F"],"docomo":null,"au":"E53F","softbank":"E232","google":"FEAF8","image":"2b06.png","sheet_x":4,"sheet_y":19,"short_name":"arrow_up","short_names":["arrow_up"],"text":null,"texts":null,"category":"Symbols","sort_order":165,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOWNWARDS BLACK ARROW","unified":"2B07","variations":["2B07-FE0F"],"docomo":null,"au":"E540","softbank":"E233","google":"FEAF9","image":"2b07.png","sheet_x":4,"sheet_y":20,"short_name":"arrow_down","short_names":["arrow_down"],"text":null,"texts":null,"category":"Symbols","sort_order":166,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK LARGE SQUARE","unified":"2B1B","variations":["2B1B-FE0F"],"docomo":null,"au":"E549","softbank":"E21A","google":"FEB6C","image":"2b1b.png","sheet_x":4,"sheet_y":21,"short_name":"black_large_square","short_names":["black_large_square"],"text":null,"texts":null,"category":"Symbols","sort_order":218,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE LARGE SQUARE","unified":"2B1C","variations":["2B1C-FE0F"],"docomo":null,"au":"E548","softbank":"E21B","google":"FEB6B","image":"2b1c.png","sheet_x":4,"sheet_y":22,"short_name":"white_large_square","short_names":["white_large_square"],"text":null,"texts":null,"category":"Symbols","sort_order":219,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE MEDIUM STAR","unified":"2B50","variations":["2B50-FE0F"],"docomo":null,"au":"E48B","softbank":"E32F","google":"FEB68","image":"2b50.png","sheet_x":4,"sheet_y":23,"short_name":"star","short_names":["star"],"text":null,"texts":null,"category":"Nature","sort_order":118,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY LARGE CIRCLE","unified":"2B55","variations":["2B55-FE0F"],"docomo":"E6A0","au":"EAAD","softbank":"E332","google":"FEB44","image":"2b55.png","sheet_x":4,"sheet_y":24,"short_name":"o","short_names":["o"],"text":null,"texts":null,"category":"Symbols","sort_order":73,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WAVY DASH","unified":"3030","variations":["3030-FE0F"],"docomo":"E709","au":null,"softbank":null,"google":"FEB07","image":"3030.png","sheet_x":4,"sheet_y":25,"short_name":"wavy_dash","short_names":["wavy_dash"],"text":null,"texts":null,"category":"Symbols","sort_order":187,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PART ALTERNATION MARK","unified":"303D","variations":["303D-FE0F"],"docomo":null,"au":null,"softbank":"E12C","google":"FE81B","image":"303d.png","sheet_x":4,"sheet_y":26,"short_name":"part_alternation_mark","short_names":["part_alternation_mark"],"text":null,"texts":null,"category":"Symbols","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCLED IDEOGRAPH CONGRATULATION","unified":"3297","variations":["3297-FE0F"],"docomo":null,"au":"EA99","softbank":"E30D","google":"FEB43","image":"3297.png","sheet_x":4,"sheet_y":27,"short_name":"congratulations","short_names":["congratulations"],"text":null,"texts":null,"category":"Symbols","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCLED IDEOGRAPH SECRET","unified":"3299","variations":["3299-FE0F"],"docomo":"E734","au":"E4F1","softbank":"E315","google":"FEB2B","image":"3299.png","sheet_x":4,"sheet_y":28,"short_name":"secret","short_names":["secret"],"text":null,"texts":null,"category":"Symbols","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MAHJONG TILE RED DRAGON","unified":"1F004","variations":["1F004-FE0F"],"docomo":null,"au":"E5D1","softbank":"E12D","google":"FE80B","image":"1f004.png","sheet_x":4,"sheet_y":29,"short_name":"mahjong","short_names":["mahjong"],"text":null,"texts":null,"category":"Symbols","sort_order":236,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PLAYING CARD BLACK JOKER","unified":"1F0CF","variations":[],"docomo":null,"au":"EB6F","softbank":null,"google":"FE812","image":"1f0cf.png","sheet_x":4,"sheet_y":30,"short_name":"black_joker","short_names":["black_joker"],"text":null,"texts":null,"category":"Symbols","sort_order":235,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED LATIN CAPITAL LETTER A","unified":"1F170","variations":["1F170-FE0F"],"docomo":null,"au":"EB26","softbank":"E532","google":"FE50B","image":"1f170.png","sheet_x":4,"sheet_y":31,"short_name":"a","short_names":["a"],"text":null,"texts":null,"category":"Symbols","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED LATIN CAPITAL LETTER B","unified":"1F171","variations":["1F171-FE0F"],"docomo":null,"au":"EB27","softbank":"E533","google":"FE50C","image":"1f171.png","sheet_x":4,"sheet_y":32,"short_name":"b","short_names":["b"],"text":null,"texts":null,"category":"Symbols","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED LATIN CAPITAL LETTER O","unified":"1F17E","variations":["1F17E-FE0F"],"docomo":null,"au":"EB28","softbank":"E535","google":"FE50E","image":"1f17e.png","sheet_x":4,"sheet_y":33,"short_name":"o2","short_names":["o2"],"text":null,"texts":null,"category":"Symbols","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED LATIN CAPITAL LETTER P","unified":"1F17F","variations":["1F17F-FE0F"],"docomo":"E66C","au":"E4A6","softbank":"E14F","google":"FE7F6","image":"1f17f.png","sheet_x":4,"sheet_y":34,"short_name":"parking","short_names":["parking"],"text":null,"texts":null,"category":"Symbols","sort_order":118,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEGATIVE SQUARED AB","unified":"1F18E","variations":[],"docomo":null,"au":"EB29","softbank":"E534","google":"FE50D","image":"1f18e.png","sheet_x":4,"sheet_y":35,"short_name":"ab","short_names":["ab"],"text":null,"texts":null,"category":"Symbols","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CL","unified":"1F191","variations":[],"docomo":"E6DB","au":"E5AB","softbank":null,"google":"FEB84","image":"1f191.png","sheet_x":4,"sheet_y":36,"short_name":"cl","short_names":["cl"],"text":null,"texts":null,"category":"Symbols","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED COOL","unified":"1F192","variations":[],"docomo":null,"au":"EA85","softbank":"E214","google":"FEB38","image":"1f192.png","sheet_x":4,"sheet_y":37,"short_name":"cool","short_names":["cool"],"text":null,"texts":null,"category":"Symbols","sort_order":131,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED FREE","unified":"1F193","variations":[],"docomo":"E6D7","au":"E578","softbank":null,"google":"FEB21","image":"1f193.png","sheet_x":4,"sheet_y":38,"short_name":"free","short_names":["free"],"text":null,"texts":null,"category":"Symbols","sort_order":133,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED ID","unified":"1F194","variations":[],"docomo":"E6D8","au":"EA88","softbank":"E229","google":"FEB81","image":"1f194.png","sheet_x":4,"sheet_y":39,"short_name":"id","short_names":["id"],"text":null,"texts":null,"category":"Symbols","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED NEW","unified":"1F195","variations":[],"docomo":"E6DD","au":"E5B5","softbank":"E212","google":"FEB36","image":"1f195.png","sheet_x":4,"sheet_y":40,"short_name":"new","short_names":["new"],"text":null,"texts":null,"category":"Symbols","sort_order":132,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED NG","unified":"1F196","variations":[],"docomo":"E72F","au":null,"softbank":null,"google":"FEB28","image":"1f196.png","sheet_x":5,"sheet_y":0,"short_name":"ng","short_names":["ng"],"text":null,"texts":null,"category":"Symbols","sort_order":128,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED OK","unified":"1F197","variations":[],"docomo":"E70B","au":"E5AD","softbank":"E24D","google":"FEB27","image":"1f197.png","sheet_x":5,"sheet_y":1,"short_name":"ok","short_names":["ok"],"text":null,"texts":null,"category":"Symbols","sort_order":129,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED SOS","unified":"1F198","variations":[],"docomo":null,"au":"E4E8","softbank":null,"google":"FEB4F","image":"1f198.png","sheet_x":5,"sheet_y":2,"short_name":"sos","short_names":["sos"],"text":null,"texts":null,"category":"Symbols","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED UP WITH EXCLAMATION MARK","unified":"1F199","variations":[],"docomo":null,"au":"E50F","softbank":"E213","google":"FEB37","image":"1f199.png","sheet_x":5,"sheet_y":3,"short_name":"up","short_names":["up"],"text":null,"texts":null,"category":"Symbols","sort_order":130,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED VS","unified":"1F19A","variations":[],"docomo":null,"au":"E5D2","softbank":"E12E","google":"FEB32","image":"1f19a.png","sheet_x":5,"sheet_y":4,"short_name":"vs","short_names":["vs"],"text":null,"texts":null,"category":"Symbols","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED KATAKANA KOKO","unified":"1F201","variations":[],"docomo":null,"au":null,"softbank":"E203","google":"FEB24","image":"1f201.png","sheet_x":5,"sheet_y":5,"short_name":"koko","short_names":["koko"],"text":null,"texts":null,"category":"Symbols","sort_order":127,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED KATAKANA SA","unified":"1F202","variations":["1F202-FE0F"],"docomo":null,"au":"EA87","softbank":"E228","google":"FEB3F","image":"1f202.png","sheet_x":5,"sheet_y":6,"short_name":"sa","short_names":["sa"],"text":null,"texts":null,"category":"Symbols","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-7121","unified":"1F21A","variations":["1F21A-FE0F"],"docomo":null,"au":null,"softbank":"E216","google":"FEB3A","image":"1f21a.png","sheet_x":5,"sheet_y":7,"short_name":"u7121","short_names":["u7121"],"text":null,"texts":null,"category":"Symbols","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-6307","unified":"1F22F","variations":["1F22F-FE0F"],"docomo":null,"au":"EA8B","softbank":"E22C","google":"FEB40","image":"1f22f.png","sheet_x":5,"sheet_y":8,"short_name":"u6307","short_names":["u6307"],"text":null,"texts":null,"category":"Symbols","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-7981","unified":"1F232","variations":[],"docomo":"E738","au":null,"softbank":null,"google":"FEB2E","image":"1f232.png","sheet_x":5,"sheet_y":9,"short_name":"u7981","short_names":["u7981"],"text":null,"texts":null,"category":"Symbols","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-7A7A","unified":"1F233","variations":[],"docomo":"E739","au":"EA8A","softbank":"E22B","google":"FEB2F","image":"1f233.png","sheet_x":5,"sheet_y":10,"short_name":"u7a7a","short_names":["u7a7a"],"text":null,"texts":null,"category":"Symbols","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-5408","unified":"1F234","variations":[],"docomo":"E73A","au":null,"softbank":null,"google":"FEB30","image":"1f234.png","sheet_x":5,"sheet_y":11,"short_name":"u5408","short_names":["u5408"],"text":null,"texts":null,"category":"Symbols","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-6E80","unified":"1F235","variations":[],"docomo":"E73B","au":"EA89","softbank":"E22A","google":"FEB31","image":"1f235.png","sheet_x":5,"sheet_y":12,"short_name":"u6e80","short_names":["u6e80"],"text":null,"texts":null,"category":"Symbols","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-6709","unified":"1F236","variations":[],"docomo":null,"au":null,"softbank":"E215","google":"FEB39","image":"1f236.png","sheet_x":5,"sheet_y":13,"short_name":"u6709","short_names":["u6709"],"text":null,"texts":null,"category":"Symbols","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-6708","unified":"1F237","variations":["1F237-FE0F"],"docomo":null,"au":null,"softbank":"E217","google":"FEB3B","image":"1f237.png","sheet_x":5,"sheet_y":14,"short_name":"u6708","short_names":["u6708"],"text":null,"texts":null,"category":"Symbols","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-7533","unified":"1F238","variations":[],"docomo":null,"au":null,"softbank":"E218","google":"FEB3C","image":"1f238.png","sheet_x":5,"sheet_y":15,"short_name":"u7533","short_names":["u7533"],"text":null,"texts":null,"category":"Symbols","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-5272","unified":"1F239","variations":[],"docomo":null,"au":"EA86","softbank":"E227","google":"FEB3E","image":"1f239.png","sheet_x":5,"sheet_y":16,"short_name":"u5272","short_names":["u5272"],"text":null,"texts":null,"category":"Symbols","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SQUARED CJK UNIFIED IDEOGRAPH-55B6","unified":"1F23A","variations":[],"docomo":null,"au":"EA8C","softbank":"E22D","google":"FEB41","image":"1f23a.png","sheet_x":5,"sheet_y":17,"short_name":"u55b6","short_names":["u55b6"],"text":null,"texts":null,"category":"Symbols","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCLED IDEOGRAPH ADVANTAGE","unified":"1F250","variations":[],"docomo":null,"au":"E4F7","softbank":"E226","google":"FEB3D","image":"1f250.png","sheet_x":5,"sheet_y":18,"short_name":"ideograph_advantage","short_names":["ideograph_advantage"],"text":null,"texts":null,"category":"Symbols","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCLED IDEOGRAPH ACCEPT","unified":"1F251","variations":[],"docomo":null,"au":"EB01","softbank":null,"google":"FEB50","image":"1f251.png","sheet_x":5,"sheet_y":19,"short_name":"accept","short_names":["accept"],"text":null,"texts":null,"category":"Symbols","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CYCLONE","unified":"1F300","variations":[],"docomo":"E643","au":"E469","softbank":"E443","google":"FE005","image":"1f300.png","sheet_x":5,"sheet_y":20,"short_name":"cyclone","short_names":["cyclone"],"text":null,"texts":null,"category":"Symbols","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FOGGY","unified":"1F301","variations":[],"docomo":"E644","au":"E598","softbank":null,"google":"FE006","image":"1f301.png","sheet_x":5,"sheet_y":21,"short_name":"foggy","short_names":["foggy"],"text":null,"texts":null,"category":"Places","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOSED UMBRELLA","unified":"1F302","variations":[],"docomo":"E645","au":"EAE8","softbank":"E43C","google":"FE007","image":"1f302.png","sheet_x":5,"sheet_y":22,"short_name":"closed_umbrella","short_names":["closed_umbrella"],"text":null,"texts":null,"category":"People","sort_order":204,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NIGHT WITH STARS","unified":"1F303","variations":[],"docomo":"E6B3","au":"EAF1","softbank":"E44B","google":"FE008","image":"1f303.png","sheet_x":5,"sheet_y":23,"short_name":"night_with_stars","short_names":["night_with_stars"],"text":null,"texts":null,"category":"Places","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUNRISE OVER MOUNTAINS","unified":"1F304","variations":[],"docomo":"E63E","au":"EAF4","softbank":"E04D","google":"FE009","image":"1f304.png","sheet_x":5,"sheet_y":24,"short_name":"sunrise_over_mountains","short_names":["sunrise_over_mountains"],"text":null,"texts":null,"category":"Places","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUNRISE","unified":"1F305","variations":[],"docomo":"E63E","au":"EAF4","softbank":"E449","google":"FE00A","image":"1f305.png","sheet_x":5,"sheet_y":25,"short_name":"sunrise","short_names":["sunrise"],"text":null,"texts":null,"category":"Places","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CITYSCAPE AT DUSK","unified":"1F306","variations":[],"docomo":null,"au":"E5DA","softbank":"E146","google":"FE00B","image":"1f306.png","sheet_x":5,"sheet_y":26,"short_name":"city_sunset","short_names":["city_sunset"],"text":null,"texts":null,"category":"Places","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUNSET OVER BUILDINGS","unified":"1F307","variations":[],"docomo":"E63E","au":"E5DA","softbank":"E44A","google":"FE00C","image":"1f307.png","sheet_x":5,"sheet_y":27,"short_name":"city_sunrise","short_names":["city_sunrise"],"text":null,"texts":null,"category":"Places","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAINBOW","unified":"1F308","variations":[],"docomo":null,"au":"EAF2","softbank":"E44C","google":"FE00D","image":"1f308.png","sheet_x":5,"sheet_y":28,"short_name":"rainbow","short_names":["rainbow"],"text":null,"texts":null,"category":"Places","sort_order":90,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BRIDGE AT NIGHT","unified":"1F309","variations":[],"docomo":"E6B3","au":"E4BF","softbank":"E44B","google":"FE010","image":"1f309.png","sheet_x":5,"sheet_y":29,"short_name":"bridge_at_night","short_names":["bridge_at_night"],"text":null,"texts":null,"category":"Places","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WATER WAVE","unified":"1F30A","variations":[],"docomo":"E73F","au":"EB7C","softbank":"E43E","google":"FE038","image":"1f30a.png","sheet_x":5,"sheet_y":30,"short_name":"ocean","short_names":["ocean"],"text":null,"texts":null,"category":"Nature","sort_order":147,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VOLCANO","unified":"1F30B","variations":[],"docomo":null,"au":"EB53","softbank":null,"google":"FE03A","image":"1f30b.png","sheet_x":5,"sheet_y":31,"short_name":"volcano","short_names":["volcano"],"text":null,"texts":null,"category":"Places","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MILKY WAY","unified":"1F30C","variations":[],"docomo":"E6B3","au":"EB5F","softbank":"E44B","google":"FE03B","image":"1f30c.png","sheet_x":5,"sheet_y":32,"short_name":"milky_way","short_names":["milky_way"],"text":null,"texts":null,"category":"Places","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EARTH GLOBE EUROPE-AFRICA","unified":"1F30D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f30d.png","sheet_x":5,"sheet_y":33,"short_name":"earth_africa","short_names":["earth_africa"],"text":null,"texts":null,"category":"Nature","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EARTH GLOBE AMERICAS","unified":"1F30E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f30e.png","sheet_x":5,"sheet_y":34,"short_name":"earth_americas","short_names":["earth_americas"],"text":null,"texts":null,"category":"Nature","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EARTH GLOBE ASIA-AUSTRALIA","unified":"1F30F","variations":[],"docomo":null,"au":"E5B3","softbank":null,"google":"FE039","image":"1f30f.png","sheet_x":5,"sheet_y":35,"short_name":"earth_asia","short_names":["earth_asia"],"text":null,"texts":null,"category":"Nature","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GLOBE WITH MERIDIANS","unified":"1F310","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f310.png","sheet_x":5,"sheet_y":36,"short_name":"globe_with_meridians","short_names":["globe_with_meridians"],"text":null,"texts":null,"category":"Symbols","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEW MOON SYMBOL","unified":"1F311","variations":[],"docomo":"E69C","au":"E5A8","softbank":null,"google":"FE011","image":"1f311.png","sheet_x":5,"sheet_y":37,"short_name":"new_moon","short_names":["new_moon"],"text":null,"texts":null,"category":"Nature","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WAXING CRESCENT MOON SYMBOL","unified":"1F312","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f312.png","sheet_x":5,"sheet_y":38,"short_name":"waxing_crescent_moon","short_names":["waxing_crescent_moon"],"text":null,"texts":null,"category":"Nature","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIRST QUARTER MOON SYMBOL","unified":"1F313","variations":[],"docomo":"E69E","au":"E5AA","softbank":"E04C","google":"FE013","image":"1f313.png","sheet_x":5,"sheet_y":39,"short_name":"first_quarter_moon","short_names":["first_quarter_moon"],"text":null,"texts":null,"category":"Nature","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WAXING GIBBOUS MOON SYMBOL","unified":"1F314","variations":[],"docomo":"E69D","au":"E5A9","softbank":"E04C","google":"FE012","image":"1f314.png","sheet_x":5,"sheet_y":40,"short_name":"moon","short_names":["moon","waxing_gibbous_moon"],"text":null,"texts":null,"category":"Nature","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FULL MOON SYMBOL","unified":"1F315","variations":[],"docomo":"E6A0","au":null,"softbank":null,"google":"FE015","image":"1f315.png","sheet_x":6,"sheet_y":0,"short_name":"full_moon","short_names":["full_moon"],"text":null,"texts":null,"category":"Nature","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WANING GIBBOUS MOON SYMBOL","unified":"1F316","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f316.png","sheet_x":6,"sheet_y":1,"short_name":"waning_gibbous_moon","short_names":["waning_gibbous_moon"],"text":null,"texts":null,"category":"Nature","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LAST QUARTER MOON SYMBOL","unified":"1F317","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f317.png","sheet_x":6,"sheet_y":2,"short_name":"last_quarter_moon","short_names":["last_quarter_moon"],"text":null,"texts":null,"category":"Nature","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WANING CRESCENT MOON SYMBOL","unified":"1F318","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f318.png","sheet_x":6,"sheet_y":3,"short_name":"waning_crescent_moon","short_names":["waning_crescent_moon"],"text":null,"texts":null,"category":"Nature","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CRESCENT MOON","unified":"1F319","variations":[],"docomo":"E69F","au":"E486","softbank":"E04C","google":"FE014","image":"1f319.png","sheet_x":6,"sheet_y":4,"short_name":"crescent_moon","short_names":["crescent_moon"],"text":null,"texts":null,"category":"Nature","sort_order":117,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEW MOON WITH FACE","unified":"1F31A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f31a.png","sheet_x":6,"sheet_y":5,"short_name":"new_moon_with_face","short_names":["new_moon_with_face"],"text":null,"texts":null,"category":"Nature","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIRST QUARTER MOON WITH FACE","unified":"1F31B","variations":[],"docomo":"E69E","au":"E489","softbank":"E04C","google":"FE016","image":"1f31b.png","sheet_x":6,"sheet_y":6,"short_name":"first_quarter_moon_with_face","short_names":["first_quarter_moon_with_face"],"text":null,"texts":null,"category":"Nature","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LAST QUARTER MOON WITH FACE","unified":"1F31C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f31c.png","sheet_x":6,"sheet_y":7,"short_name":"last_quarter_moon_with_face","short_names":["last_quarter_moon_with_face"],"text":null,"texts":null,"category":"Nature","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FULL MOON WITH FACE","unified":"1F31D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f31d.png","sheet_x":6,"sheet_y":8,"short_name":"full_moon_with_face","short_names":["full_moon_with_face"],"text":null,"texts":null,"category":"Nature","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUN WITH FACE","unified":"1F31E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f31e.png","sheet_x":6,"sheet_y":9,"short_name":"sun_with_face","short_names":["sun_with_face"],"text":null,"texts":null,"category":"Nature","sort_order":116,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GLOWING STAR","unified":"1F31F","variations":[],"docomo":null,"au":"E48B","softbank":"E335","google":"FEB69","image":"1f31f.png","sheet_x":6,"sheet_y":10,"short_name":"star2","short_names":["star2"],"text":null,"texts":null,"category":"Nature","sort_order":119,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHOOTING STAR","unified":"1F320","variations":[],"docomo":null,"au":"E468","softbank":null,"google":"FEB6A","image":"1f320.png","sheet_x":6,"sheet_y":11,"short_name":"stars","short_names":["stars"],"text":null,"texts":null,"category":"Places","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"THERMOMETER","unified":"1F321","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f321.png","sheet_x":6,"sheet_y":12,"short_name":"thermometer","short_names":["thermometer"],"text":null,"texts":null,"category":"Objects","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SUN WITH SMALL CLOUD","unified":"1F324","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f324.png","sheet_x":6,"sheet_y":13,"short_name":"mostly_sunny","short_names":["mostly_sunny","sun_small_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":124,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SUN BEHIND CLOUD","unified":"1F325","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f325.png","sheet_x":6,"sheet_y":14,"short_name":"barely_sunny","short_names":["barely_sunny","sun_behind_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":126,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SUN BEHIND CLOUD WITH RAIN","unified":"1F326","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f326.png","sheet_x":6,"sheet_y":15,"short_name":"partly_sunny_rain","short_names":["partly_sunny_rain","sun_behind_rain_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":127,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOUD WITH RAIN","unified":"1F327","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f327.png","sheet_x":6,"sheet_y":16,"short_name":"rain_cloud","short_names":["rain_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":129,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOUD WITH SNOW","unified":"1F328","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f328.png","sheet_x":6,"sheet_y":17,"short_name":"snow_cloud","short_names":["snow_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":136,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOUD WITH LIGHTNING","unified":"1F329","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f329.png","sheet_x":6,"sheet_y":18,"short_name":"lightning","short_names":["lightning","lightning_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":131,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOUD WITH TORNADO","unified":"1F32A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32a.png","sheet_x":6,"sheet_y":19,"short_name":"tornado","short_names":["tornado","tornado_cloud"],"text":null,"texts":null,"category":"Nature","sort_order":141,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FOG","unified":"1F32B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32b.png","sheet_x":6,"sheet_y":20,"short_name":"fog","short_names":["fog"],"text":null,"texts":null,"category":"Nature","sort_order":142,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WIND BLOWING FACE","unified":"1F32C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32c.png","sheet_x":6,"sheet_y":21,"short_name":"wind_blowing_face","short_names":["wind_blowing_face"],"text":null,"texts":null,"category":"Nature","sort_order":139,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOT DOG","unified":"1F32D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32d.png","sheet_x":6,"sheet_y":22,"short_name":"hotdog","short_names":["hotdog"],"text":null,"texts":null,"category":"Foods","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TACO","unified":"1F32E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32e.png","sheet_x":6,"sheet_y":23,"short_name":"taco","short_names":["taco"],"text":null,"texts":null,"category":"Foods","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BURRITO","unified":"1F32F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f32f.png","sheet_x":6,"sheet_y":24,"short_name":"burrito","short_names":["burrito"],"text":null,"texts":null,"category":"Foods","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHESTNUT","unified":"1F330","variations":[],"docomo":null,"au":"EB38","softbank":null,"google":"FE04C","image":"1f330.png","sheet_x":6,"sheet_y":25,"short_name":"chestnut","short_names":["chestnut"],"text":null,"texts":null,"category":"Nature","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SEEDLING","unified":"1F331","variations":[],"docomo":"E746","au":"EB7D","softbank":"E110","google":"FE03E","image":"1f331.png","sheet_x":6,"sheet_y":26,"short_name":"seedling","short_names":["seedling"],"text":null,"texts":null,"category":"Nature","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EVERGREEN TREE","unified":"1F332","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f332.png","sheet_x":6,"sheet_y":27,"short_name":"evergreen_tree","short_names":["evergreen_tree"],"text":null,"texts":null,"category":"Nature","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DECIDUOUS TREE","unified":"1F333","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f333.png","sheet_x":6,"sheet_y":28,"short_name":"deciduous_tree","short_names":["deciduous_tree"],"text":null,"texts":null,"category":"Nature","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PALM TREE","unified":"1F334","variations":[],"docomo":null,"au":"E4E2","softbank":"E307","google":"FE047","image":"1f334.png","sheet_x":6,"sheet_y":29,"short_name":"palm_tree","short_names":["palm_tree"],"text":null,"texts":null,"category":"Nature","sort_order":78,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CACTUS","unified":"1F335","variations":[],"docomo":null,"au":"EA96","softbank":"E308","google":"FE048","image":"1f335.png","sheet_x":6,"sheet_y":30,"short_name":"cactus","short_names":["cactus"],"text":null,"texts":null,"category":"Nature","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOT PEPPER","unified":"1F336","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f336.png","sheet_x":6,"sheet_y":31,"short_name":"hot_pepper","short_names":["hot_pepper"],"text":null,"texts":null,"category":"Foods","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TULIP","unified":"1F337","variations":[],"docomo":"E743","au":"E4E4","softbank":"E304","google":"FE03D","image":"1f337.png","sheet_x":6,"sheet_y":32,"short_name":"tulip","short_names":["tulip"],"text":null,"texts":null,"category":"Nature","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHERRY BLOSSOM","unified":"1F338","variations":[],"docomo":"E748","au":"E4CA","softbank":"E030","google":"FE040","image":"1f338.png","sheet_x":6,"sheet_y":33,"short_name":"cherry_blossom","short_names":["cherry_blossom"],"text":null,"texts":null,"category":"Nature","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROSE","unified":"1F339","variations":[],"docomo":null,"au":"E5BA","softbank":"E032","google":"FE041","image":"1f339.png","sheet_x":6,"sheet_y":34,"short_name":"rose","short_names":["rose"],"text":null,"texts":null,"category":"Nature","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIBISCUS","unified":"1F33A","variations":[],"docomo":null,"au":"EA94","softbank":"E303","google":"FE045","image":"1f33a.png","sheet_x":6,"sheet_y":35,"short_name":"hibiscus","short_names":["hibiscus"],"text":null,"texts":null,"category":"Nature","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUNFLOWER","unified":"1F33B","variations":[],"docomo":null,"au":"E4E3","softbank":"E305","google":"FE046","image":"1f33b.png","sheet_x":6,"sheet_y":36,"short_name":"sunflower","short_names":["sunflower"],"text":null,"texts":null,"category":"Nature","sort_order":90,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLOSSOM","unified":"1F33C","variations":[],"docomo":null,"au":"EB49","softbank":"E305","google":"FE04D","image":"1f33c.png","sheet_x":6,"sheet_y":37,"short_name":"blossom","short_names":["blossom"],"text":null,"texts":null,"category":"Nature","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EAR OF MAIZE","unified":"1F33D","variations":[],"docomo":null,"au":"EB36","softbank":null,"google":"FE04A","image":"1f33d.png","sheet_x":6,"sheet_y":38,"short_name":"corn","short_names":["corn"],"text":null,"texts":null,"category":"Foods","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EAR OF RICE","unified":"1F33E","variations":[],"docomo":null,"au":null,"softbank":"E444","google":"FE049","image":"1f33e.png","sheet_x":6,"sheet_y":39,"short_name":"ear_of_rice","short_names":["ear_of_rice"],"text":null,"texts":null,"category":"Nature","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HERB","unified":"1F33F","variations":[],"docomo":"E741","au":"EB82","softbank":"E110","google":"FE04E","image":"1f33f.png","sheet_x":6,"sheet_y":40,"short_name":"herb","short_names":["herb"],"text":null,"texts":null,"category":"Nature","sort_order":80,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FOUR LEAF CLOVER","unified":"1F340","variations":[],"docomo":"E741","au":"E513","softbank":"E110","google":"FE03C","image":"1f340.png","sheet_x":7,"sheet_y":0,"short_name":"four_leaf_clover","short_names":["four_leaf_clover"],"text":null,"texts":null,"category":"Nature","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MAPLE LEAF","unified":"1F341","variations":[],"docomo":"E747","au":"E4CE","softbank":"E118","google":"FE03F","image":"1f341.png","sheet_x":7,"sheet_y":1,"short_name":"maple_leaf","short_names":["maple_leaf"],"text":null,"texts":null,"category":"Nature","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FALLEN LEAF","unified":"1F342","variations":[],"docomo":"E747","au":"E5CD","softbank":"E119","google":"FE042","image":"1f342.png","sheet_x":7,"sheet_y":2,"short_name":"fallen_leaf","short_names":["fallen_leaf"],"text":null,"texts":null,"category":"Nature","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEAF FLUTTERING IN WIND","unified":"1F343","variations":[],"docomo":null,"au":"E5CD","softbank":"E447","google":"FE043","image":"1f343.png","sheet_x":7,"sheet_y":3,"short_name":"leaves","short_names":["leaves"],"text":null,"texts":null,"category":"Nature","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MUSHROOM","unified":"1F344","variations":[],"docomo":null,"au":"EB37","softbank":null,"google":"FE04B","image":"1f344.png","sheet_x":7,"sheet_y":4,"short_name":"mushroom","short_names":["mushroom"],"text":null,"texts":null,"category":"Nature","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TOMATO","unified":"1F345","variations":[],"docomo":null,"au":"EABB","softbank":"E349","google":"FE055","image":"1f345.png","sheet_x":7,"sheet_y":5,"short_name":"tomato","short_names":["tomato"],"text":null,"texts":null,"category":"Foods","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AUBERGINE","unified":"1F346","variations":[],"docomo":null,"au":"EABC","softbank":"E34A","google":"FE056","image":"1f346.png","sheet_x":7,"sheet_y":6,"short_name":"eggplant","short_names":["eggplant"],"text":null,"texts":null,"category":"Foods","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRAPES","unified":"1F347","variations":[],"docomo":null,"au":"EB34","softbank":null,"google":"FE059","image":"1f347.png","sheet_x":7,"sheet_y":7,"short_name":"grapes","short_names":["grapes"],"text":null,"texts":null,"category":"Foods","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MELON","unified":"1F348","variations":[],"docomo":null,"au":"EB32","softbank":null,"google":"FE057","image":"1f348.png","sheet_x":7,"sheet_y":8,"short_name":"melon","short_names":["melon"],"text":null,"texts":null,"category":"Foods","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WATERMELON","unified":"1F349","variations":[],"docomo":null,"au":"E4CD","softbank":"E348","google":"FE054","image":"1f349.png","sheet_x":7,"sheet_y":9,"short_name":"watermelon","short_names":["watermelon"],"text":null,"texts":null,"category":"Foods","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TANGERINE","unified":"1F34A","variations":[],"docomo":null,"au":"EABA","softbank":"E346","google":"FE052","image":"1f34a.png","sheet_x":7,"sheet_y":10,"short_name":"tangerine","short_names":["tangerine"],"text":null,"texts":null,"category":"Foods","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEMON","unified":"1F34B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f34b.png","sheet_x":7,"sheet_y":11,"short_name":"lemon","short_names":["lemon"],"text":null,"texts":null,"category":"Foods","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANANA","unified":"1F34C","variations":[],"docomo":"E744","au":"EB35","softbank":null,"google":"FE050","image":"1f34c.png","sheet_x":7,"sheet_y":12,"short_name":"banana","short_names":["banana"],"text":null,"texts":null,"category":"Foods","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PINEAPPLE","unified":"1F34D","variations":[],"docomo":null,"au":"EB33","softbank":null,"google":"FE058","image":"1f34d.png","sheet_x":7,"sheet_y":13,"short_name":"pineapple","short_names":["pineapple"],"text":null,"texts":null,"category":"Foods","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RED APPLE","unified":"1F34E","variations":[],"docomo":"E745","au":"EAB9","softbank":"E345","google":"FE051","image":"1f34e.png","sheet_x":7,"sheet_y":14,"short_name":"apple","short_names":["apple"],"text":null,"texts":null,"category":"Foods","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GREEN APPLE","unified":"1F34F","variations":[],"docomo":"E745","au":"EB5A","softbank":"E345","google":"FE05B","image":"1f34f.png","sheet_x":7,"sheet_y":15,"short_name":"green_apple","short_names":["green_apple"],"text":null,"texts":null,"category":"Foods","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PEAR","unified":"1F350","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f350.png","sheet_x":7,"sheet_y":16,"short_name":"pear","short_names":["pear"],"text":null,"texts":null,"category":"Foods","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PEACH","unified":"1F351","variations":[],"docomo":null,"au":"EB39","softbank":null,"google":"FE05A","image":"1f351.png","sheet_x":7,"sheet_y":17,"short_name":"peach","short_names":["peach"],"text":null,"texts":null,"category":"Foods","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHERRIES","unified":"1F352","variations":[],"docomo":"E742","au":"E4D2","softbank":null,"google":"FE04F","image":"1f352.png","sheet_x":7,"sheet_y":18,"short_name":"cherries","short_names":["cherries"],"text":null,"texts":null,"category":"Foods","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STRAWBERRY","unified":"1F353","variations":[],"docomo":null,"au":"E4D4","softbank":"E347","google":"FE053","image":"1f353.png","sheet_x":7,"sheet_y":19,"short_name":"strawberry","short_names":["strawberry"],"text":null,"texts":null,"category":"Foods","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAMBURGER","unified":"1F354","variations":[],"docomo":"E673","au":"E4D6","softbank":"E120","google":"FE960","image":"1f354.png","sheet_x":7,"sheet_y":20,"short_name":"hamburger","short_names":["hamburger"],"text":null,"texts":null,"category":"Foods","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLICE OF PIZZA","unified":"1F355","variations":[],"docomo":null,"au":"EB3B","softbank":null,"google":"FE975","image":"1f355.png","sheet_x":7,"sheet_y":21,"short_name":"pizza","short_names":["pizza"],"text":null,"texts":null,"category":"Foods","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MEAT ON BONE","unified":"1F356","variations":[],"docomo":null,"au":"E4C4","softbank":null,"google":"FE972","image":"1f356.png","sheet_x":7,"sheet_y":22,"short_name":"meat_on_bone","short_names":["meat_on_bone"],"text":null,"texts":null,"category":"Foods","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POULTRY LEG","unified":"1F357","variations":[],"docomo":null,"au":"EB3C","softbank":null,"google":"FE976","image":"1f357.png","sheet_x":7,"sheet_y":23,"short_name":"poultry_leg","short_names":["poultry_leg"],"text":null,"texts":null,"category":"Foods","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RICE CRACKER","unified":"1F358","variations":[],"docomo":null,"au":"EAB3","softbank":"E33D","google":"FE969","image":"1f358.png","sheet_x":7,"sheet_y":24,"short_name":"rice_cracker","short_names":["rice_cracker"],"text":null,"texts":null,"category":"Foods","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RICE BALL","unified":"1F359","variations":[],"docomo":"E749","au":"E4D5","softbank":"E342","google":"FE961","image":"1f359.png","sheet_x":7,"sheet_y":25,"short_name":"rice_ball","short_names":["rice_ball"],"text":null,"texts":null,"category":"Foods","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COOKED RICE","unified":"1F35A","variations":[],"docomo":"E74C","au":"EAB4","softbank":"E33E","google":"FE96A","image":"1f35a.png","sheet_x":7,"sheet_y":26,"short_name":"rice","short_names":["rice"],"text":null,"texts":null,"category":"Foods","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CURRY AND RICE","unified":"1F35B","variations":[],"docomo":null,"au":"EAB6","softbank":"E341","google":"FE96C","image":"1f35b.png","sheet_x":7,"sheet_y":27,"short_name":"curry","short_names":["curry"],"text":null,"texts":null,"category":"Foods","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STEAMING BOWL","unified":"1F35C","variations":[],"docomo":"E74C","au":"E5B4","softbank":"E340","google":"FE963","image":"1f35c.png","sheet_x":7,"sheet_y":28,"short_name":"ramen","short_names":["ramen"],"text":null,"texts":null,"category":"Foods","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPAGHETTI","unified":"1F35D","variations":[],"docomo":null,"au":"EAB5","softbank":"E33F","google":"FE96B","image":"1f35d.png","sheet_x":7,"sheet_y":29,"short_name":"spaghetti","short_names":["spaghetti"],"text":null,"texts":null,"category":"Foods","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BREAD","unified":"1F35E","variations":[],"docomo":"E74D","au":"EAAF","softbank":"E339","google":"FE964","image":"1f35e.png","sheet_x":7,"sheet_y":30,"short_name":"bread","short_names":["bread"],"text":null,"texts":null,"category":"Foods","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FRENCH FRIES","unified":"1F35F","variations":[],"docomo":null,"au":"EAB1","softbank":"E33B","google":"FE967","image":"1f35f.png","sheet_x":7,"sheet_y":31,"short_name":"fries","short_names":["fries"],"text":null,"texts":null,"category":"Foods","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROASTED SWEET POTATO","unified":"1F360","variations":[],"docomo":null,"au":"EB3A","softbank":null,"google":"FE974","image":"1f360.png","sheet_x":7,"sheet_y":32,"short_name":"sweet_potato","short_names":["sweet_potato"],"text":null,"texts":null,"category":"Foods","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DANGO","unified":"1F361","variations":[],"docomo":null,"au":"EAB2","softbank":"E33C","google":"FE968","image":"1f361.png","sheet_x":7,"sheet_y":33,"short_name":"dango","short_names":["dango"],"text":null,"texts":null,"category":"Foods","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ODEN","unified":"1F362","variations":[],"docomo":null,"au":"EAB7","softbank":"E343","google":"FE96D","image":"1f362.png","sheet_x":7,"sheet_y":34,"short_name":"oden","short_names":["oden"],"text":null,"texts":null,"category":"Foods","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUSHI","unified":"1F363","variations":[],"docomo":null,"au":"EAB8","softbank":"E344","google":"FE96E","image":"1f363.png","sheet_x":7,"sheet_y":35,"short_name":"sushi","short_names":["sushi"],"text":null,"texts":null,"category":"Foods","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FRIED SHRIMP","unified":"1F364","variations":[],"docomo":null,"au":"EB70","softbank":null,"google":"FE97F","image":"1f364.png","sheet_x":7,"sheet_y":36,"short_name":"fried_shrimp","short_names":["fried_shrimp"],"text":null,"texts":null,"category":"Foods","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FISH CAKE WITH SWIRL DESIGN","unified":"1F365","variations":[],"docomo":"E643","au":"E4ED","softbank":null,"google":"FE973","image":"1f365.png","sheet_x":7,"sheet_y":37,"short_name":"fish_cake","short_names":["fish_cake"],"text":null,"texts":null,"category":"Foods","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SOFT ICE CREAM","unified":"1F366","variations":[],"docomo":null,"au":"EAB0","softbank":"E33A","google":"FE966","image":"1f366.png","sheet_x":7,"sheet_y":38,"short_name":"icecream","short_names":["icecream"],"text":null,"texts":null,"category":"Foods","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHAVED ICE","unified":"1F367","variations":[],"docomo":null,"au":"EAEA","softbank":"E43F","google":"FE971","image":"1f367.png","sheet_x":7,"sheet_y":39,"short_name":"shaved_ice","short_names":["shaved_ice"],"text":null,"texts":null,"category":"Foods","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ICE CREAM","unified":"1F368","variations":[],"docomo":null,"au":"EB4A","softbank":null,"google":"FE977","image":"1f368.png","sheet_x":7,"sheet_y":40,"short_name":"ice_cream","short_names":["ice_cream"],"text":null,"texts":null,"category":"Foods","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOUGHNUT","unified":"1F369","variations":[],"docomo":null,"au":"EB4B","softbank":null,"google":"FE978","image":"1f369.png","sheet_x":8,"sheet_y":0,"short_name":"doughnut","short_names":["doughnut"],"text":null,"texts":null,"category":"Foods","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COOKIE","unified":"1F36A","variations":[],"docomo":null,"au":"EB4C","softbank":null,"google":"FE979","image":"1f36a.png","sheet_x":8,"sheet_y":1,"short_name":"cookie","short_names":["cookie"],"text":null,"texts":null,"category":"Foods","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHOCOLATE BAR","unified":"1F36B","variations":[],"docomo":null,"au":"EB4D","softbank":null,"google":"FE97A","image":"1f36b.png","sheet_x":8,"sheet_y":2,"short_name":"chocolate_bar","short_names":["chocolate_bar"],"text":null,"texts":null,"category":"Foods","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CANDY","unified":"1F36C","variations":[],"docomo":null,"au":"EB4E","softbank":null,"google":"FE97B","image":"1f36c.png","sheet_x":8,"sheet_y":3,"short_name":"candy","short_names":["candy"],"text":null,"texts":null,"category":"Foods","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOLLIPOP","unified":"1F36D","variations":[],"docomo":null,"au":"EB4F","softbank":null,"google":"FE97C","image":"1f36d.png","sheet_x":8,"sheet_y":4,"short_name":"lollipop","short_names":["lollipop"],"text":null,"texts":null,"category":"Foods","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CUSTARD","unified":"1F36E","variations":[],"docomo":null,"au":"EB56","softbank":null,"google":"FE97D","image":"1f36e.png","sheet_x":8,"sheet_y":5,"short_name":"custard","short_names":["custard"],"text":null,"texts":null,"category":"Foods","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HONEY POT","unified":"1F36F","variations":[],"docomo":null,"au":"EB59","softbank":null,"google":"FE97E","image":"1f36f.png","sheet_x":8,"sheet_y":6,"short_name":"honey_pot","short_names":["honey_pot"],"text":null,"texts":null,"category":"Foods","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHORTCAKE","unified":"1F370","variations":[],"docomo":"E74A","au":"E4D0","softbank":"E046","google":"FE962","image":"1f370.png","sheet_x":8,"sheet_y":7,"short_name":"cake","short_names":["cake"],"text":null,"texts":null,"category":"Foods","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BENTO BOX","unified":"1F371","variations":[],"docomo":null,"au":"EABD","softbank":"E34C","google":"FE96F","image":"1f371.png","sheet_x":8,"sheet_y":8,"short_name":"bento","short_names":["bento"],"text":null,"texts":null,"category":"Foods","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POT OF FOOD","unified":"1F372","variations":[],"docomo":null,"au":"EABE","softbank":"E34D","google":"FE970","image":"1f372.png","sheet_x":8,"sheet_y":9,"short_name":"stew","short_names":["stew"],"text":null,"texts":null,"category":"Foods","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COOKING","unified":"1F373","variations":[],"docomo":null,"au":"E4D1","softbank":"E147","google":"FE965","image":"1f373.png","sheet_x":8,"sheet_y":10,"short_name":"egg","short_names":["egg"],"text":null,"texts":null,"category":"Foods","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FORK AND KNIFE","unified":"1F374","variations":[],"docomo":"E66F","au":"E4AC","softbank":"E043","google":"FE980","image":"1f374.png","sheet_x":8,"sheet_y":11,"short_name":"fork_and_knife","short_names":["fork_and_knife"],"text":null,"texts":null,"category":"Foods","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TEACUP WITHOUT HANDLE","unified":"1F375","variations":[],"docomo":"E71E","au":"EAAE","softbank":"E338","google":"FE984","image":"1f375.png","sheet_x":8,"sheet_y":12,"short_name":"tea","short_names":["tea"],"text":null,"texts":null,"category":"Foods","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SAKE BOTTLE AND CUP","unified":"1F376","variations":[],"docomo":"E74B","au":"EA97","softbank":"E30B","google":"FE985","image":"1f376.png","sheet_x":8,"sheet_y":13,"short_name":"sake","short_names":["sake"],"text":null,"texts":null,"category":"Foods","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WINE GLASS","unified":"1F377","variations":[],"docomo":"E756","au":"E4C1","softbank":"E044","google":"FE986","image":"1f377.png","sheet_x":8,"sheet_y":14,"short_name":"wine_glass","short_names":["wine_glass"],"text":null,"texts":null,"category":"Foods","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COCKTAIL GLASS","unified":"1F378","variations":[],"docomo":"E671","au":"E4C2","softbank":"E044","google":"FE982","image":"1f378.png","sheet_x":8,"sheet_y":15,"short_name":"cocktail","short_names":["cocktail"],"text":null,"texts":null,"category":"Foods","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TROPICAL DRINK","unified":"1F379","variations":[],"docomo":"E671","au":"EB3E","softbank":"E044","google":"FE988","image":"1f379.png","sheet_x":8,"sheet_y":16,"short_name":"tropical_drink","short_names":["tropical_drink"],"text":null,"texts":null,"category":"Foods","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BEER MUG","unified":"1F37A","variations":[],"docomo":"E672","au":"E4C3","softbank":"E047","google":"FE983","image":"1f37a.png","sheet_x":8,"sheet_y":17,"short_name":"beer","short_names":["beer"],"text":null,"texts":null,"category":"Foods","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLINKING BEER MUGS","unified":"1F37B","variations":[],"docomo":"E672","au":"EA98","softbank":"E30C","google":"FE987","image":"1f37b.png","sheet_x":8,"sheet_y":18,"short_name":"beers","short_names":["beers"],"text":null,"texts":null,"category":"Foods","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BABY BOTTLE","unified":"1F37C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f37c.png","sheet_x":8,"sheet_y":19,"short_name":"baby_bottle","short_names":["baby_bottle"],"text":null,"texts":null,"category":"Foods","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FORK AND KNIFE WITH PLATE","unified":"1F37D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f37d.png","sheet_x":8,"sheet_y":20,"short_name":"knife_fork_plate","short_names":["knife_fork_plate"],"text":null,"texts":null,"category":"Foods","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOTTLE WITH POPPING CORK","unified":"1F37E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f37e.png","sheet_x":8,"sheet_y":21,"short_name":"champagne","short_names":["champagne"],"text":null,"texts":null,"category":"Foods","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POPCORN","unified":"1F37F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f37f.png","sheet_x":8,"sheet_y":22,"short_name":"popcorn","short_names":["popcorn"],"text":null,"texts":null,"category":"Foods","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RIBBON","unified":"1F380","variations":[],"docomo":"E684","au":"E59F","softbank":"E314","google":"FE50F","image":"1f380.png","sheet_x":8,"sheet_y":23,"short_name":"ribbon","short_names":["ribbon"],"text":null,"texts":null,"category":"Objects","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WRAPPED PRESENT","unified":"1F381","variations":[],"docomo":"E685","au":"E4CF","softbank":"E112","google":"FE510","image":"1f381.png","sheet_x":8,"sheet_y":24,"short_name":"gift","short_names":["gift"],"text":null,"texts":null,"category":"Objects","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BIRTHDAY CAKE","unified":"1F382","variations":[],"docomo":"E686","au":"E5A0","softbank":"E34B","google":"FE511","image":"1f382.png","sheet_x":8,"sheet_y":25,"short_name":"birthday","short_names":["birthday"],"text":null,"texts":null,"category":"Foods","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JACK-O-LANTERN","unified":"1F383","variations":[],"docomo":null,"au":"EAEE","softbank":"E445","google":"FE51F","image":"1f383.png","sheet_x":8,"sheet_y":26,"short_name":"jack_o_lantern","short_names":["jack_o_lantern"],"text":null,"texts":null,"category":"Nature","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHRISTMAS TREE","unified":"1F384","variations":[],"docomo":"E6A4","au":"E4C9","softbank":"E033","google":"FE512","image":"1f384.png","sheet_x":8,"sheet_y":27,"short_name":"christmas_tree","short_names":["christmas_tree"],"text":null,"texts":null,"category":"Nature","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FATHER CHRISTMAS","unified":"1F385","variations":[],"docomo":null,"au":"EAF0","softbank":"E448","google":"FE513","image":"1f385.png","sheet_x":8,"sheet_y":28,"short_name":"santa","short_names":["santa"],"text":null,"texts":null,"category":"People","sort_order":135,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F385-1F3FB":{"unified":"1F385-1F3FB","image":"1f385-1f3fb.png","sheet_x":8,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F385-1F3FC":{"unified":"1F385-1F3FC","image":"1f385-1f3fc.png","sheet_x":8,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F385-1F3FD":{"unified":"1F385-1F3FD","image":"1f385-1f3fd.png","sheet_x":8,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F385-1F3FE":{"unified":"1F385-1F3FE","image":"1f385-1f3fe.png","sheet_x":8,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F385-1F3FF":{"unified":"1F385-1F3FF","image":"1f385-1f3ff.png","sheet_x":8,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"FIREWORKS","unified":"1F386","variations":[],"docomo":null,"au":"E5CC","softbank":"E117","google":"FE515","image":"1f386.png","sheet_x":8,"sheet_y":34,"short_name":"fireworks","short_names":["fireworks"],"text":null,"texts":null,"category":"Places","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIREWORK SPARKLER","unified":"1F387","variations":[],"docomo":null,"au":"EAEB","softbank":"E440","google":"FE51D","image":"1f387.png","sheet_x":8,"sheet_y":35,"short_name":"sparkler","short_names":["sparkler"],"text":null,"texts":null,"category":"Places","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BALLOON","unified":"1F388","variations":[],"docomo":null,"au":"EA9B","softbank":"E310","google":"FE516","image":"1f388.png","sheet_x":8,"sheet_y":36,"short_name":"balloon","short_names":["balloon"],"text":null,"texts":null,"category":"Objects","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PARTY POPPER","unified":"1F389","variations":[],"docomo":null,"au":"EA9C","softbank":"E312","google":"FE517","image":"1f389.png","sheet_x":8,"sheet_y":37,"short_name":"tada","short_names":["tada"],"text":null,"texts":null,"category":"Objects","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONFETTI BALL","unified":"1F38A","variations":[],"docomo":null,"au":"E46F","softbank":null,"google":"FE520","image":"1f38a.png","sheet_x":8,"sheet_y":38,"short_name":"confetti_ball","short_names":["confetti_ball"],"text":null,"texts":null,"category":"Objects","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TANABATA TREE","unified":"1F38B","variations":[],"docomo":null,"au":"EB3D","softbank":null,"google":"FE521","image":"1f38b.png","sheet_x":8,"sheet_y":39,"short_name":"tanabata_tree","short_names":["tanabata_tree"],"text":null,"texts":null,"category":"Nature","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CROSSED FLAGS","unified":"1F38C","variations":[],"docomo":null,"au":"E5D9","softbank":"E143","google":"FE514","image":"1f38c.png","sheet_x":8,"sheet_y":40,"short_name":"crossed_flags","short_names":["crossed_flags"],"text":null,"texts":null,"category":"Objects","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PINE DECORATION","unified":"1F38D","variations":[],"docomo":null,"au":"EAE3","softbank":"E436","google":"FE518","image":"1f38d.png","sheet_x":9,"sheet_y":0,"short_name":"bamboo","short_names":["bamboo"],"text":null,"texts":null,"category":"Nature","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JAPANESE DOLLS","unified":"1F38E","variations":[],"docomo":null,"au":"EAE4","softbank":"E438","google":"FE519","image":"1f38e.png","sheet_x":9,"sheet_y":1,"short_name":"dolls","short_names":["dolls"],"text":null,"texts":null,"category":"Objects","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CARP STREAMER","unified":"1F38F","variations":[],"docomo":null,"au":"EAE7","softbank":"E43B","google":"FE51C","image":"1f38f.png","sheet_x":9,"sheet_y":2,"short_name":"flags","short_names":["flags"],"text":null,"texts":null,"category":"Objects","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WIND CHIME","unified":"1F390","variations":[],"docomo":null,"au":"EAED","softbank":"E442","google":"FE51E","image":"1f390.png","sheet_x":9,"sheet_y":3,"short_name":"wind_chime","short_names":["wind_chime"],"text":null,"texts":null,"category":"Objects","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOON VIEWING CEREMONY","unified":"1F391","variations":[],"docomo":null,"au":"EAEF","softbank":"E446","google":"FE017","image":"1f391.png","sheet_x":9,"sheet_y":4,"short_name":"rice_scene","short_names":["rice_scene"],"text":null,"texts":null,"category":"Places","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCHOOL SATCHEL","unified":"1F392","variations":[],"docomo":null,"au":"EAE6","softbank":"E43A","google":"FE51B","image":"1f392.png","sheet_x":9,"sheet_y":5,"short_name":"school_satchel","short_names":["school_satchel"],"text":null,"texts":null,"category":"People","sort_order":196,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRADUATION CAP","unified":"1F393","variations":[],"docomo":null,"au":"EAE5","softbank":"E439","google":"FE51A","image":"1f393.png","sheet_x":9,"sheet_y":6,"short_name":"mortar_board","short_names":["mortar_board"],"text":null,"texts":null,"category":"People","sort_order":194,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MILITARY MEDAL","unified":"1F396","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f396.png","sheet_x":9,"sheet_y":7,"short_name":"medal","short_names":["medal"],"text":null,"texts":null,"category":"Activity","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REMINDER RIBBON","unified":"1F397","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f397.png","sheet_x":9,"sheet_y":8,"short_name":"reminder_ribbon","short_names":["reminder_ribbon"],"text":null,"texts":null,"category":"Activity","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STUDIO MICROPHONE","unified":"1F399","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f399.png","sheet_x":9,"sheet_y":9,"short_name":"studio_microphone","short_names":["studio_microphone"],"text":null,"texts":null,"category":"Objects","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEVEL SLIDER","unified":"1F39A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f39a.png","sheet_x":9,"sheet_y":10,"short_name":"level_slider","short_names":["level_slider"],"text":null,"texts":null,"category":"Objects","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONTROL KNOBS","unified":"1F39B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f39b.png","sheet_x":9,"sheet_y":11,"short_name":"control_knobs","short_names":["control_knobs"],"text":null,"texts":null,"category":"Objects","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FILM FRAMES","unified":"1F39E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f39e.png","sheet_x":9,"sheet_y":12,"short_name":"film_frames","short_names":["film_frames"],"text":null,"texts":null,"category":"Objects","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ADMISSION TICKETS","unified":"1F39F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f39f.png","sheet_x":9,"sheet_y":13,"short_name":"admission_tickets","short_names":["admission_tickets"],"text":null,"texts":null,"category":"Activity","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAROUSEL HORSE","unified":"1F3A0","variations":[],"docomo":"E679","au":null,"softbank":null,"google":"FE7FC","image":"1f3a0.png","sheet_x":9,"sheet_y":14,"short_name":"carousel_horse","short_names":["carousel_horse"],"text":null,"texts":null,"category":"Places","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FERRIS WHEEL","unified":"1F3A1","variations":[],"docomo":null,"au":"E46D","softbank":"E124","google":"FE7FD","image":"1f3a1.png","sheet_x":9,"sheet_y":15,"short_name":"ferris_wheel","short_names":["ferris_wheel"],"text":null,"texts":null,"category":"Places","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROLLER COASTER","unified":"1F3A2","variations":[],"docomo":null,"au":"EAE2","softbank":"E433","google":"FE7FE","image":"1f3a2.png","sheet_x":9,"sheet_y":16,"short_name":"roller_coaster","short_names":["roller_coaster"],"text":null,"texts":null,"category":"Places","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FISHING POLE AND FISH","unified":"1F3A3","variations":[],"docomo":"E751","au":"EB42","softbank":"E019","google":"FE7FF","image":"1f3a3.png","sheet_x":9,"sheet_y":17,"short_name":"fishing_pole_and_fish","short_names":["fishing_pole_and_fish"],"text":null,"texts":null,"category":"Activity","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MICROPHONE","unified":"1F3A4","variations":[],"docomo":"E676","au":"E503","softbank":"E03C","google":"FE800","image":"1f3a4.png","sheet_x":9,"sheet_y":18,"short_name":"microphone","short_names":["microphone"],"text":null,"texts":null,"category":"Activity","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOVIE CAMERA","unified":"1F3A5","variations":[],"docomo":"E677","au":"E517","softbank":"E03D","google":"FE801","image":"1f3a5.png","sheet_x":9,"sheet_y":19,"short_name":"movie_camera","short_names":["movie_camera"],"text":null,"texts":null,"category":"Objects","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CINEMA","unified":"1F3A6","variations":[],"docomo":"E677","au":"E517","softbank":"E507","google":"FE802","image":"1f3a6.png","sheet_x":9,"sheet_y":20,"short_name":"cinema","short_names":["cinema"],"text":null,"texts":null,"category":"Symbols","sort_order":125,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEADPHONE","unified":"1F3A7","variations":[],"docomo":"E67A","au":"E508","softbank":"E30A","google":"FE803","image":"1f3a7.png","sheet_x":9,"sheet_y":21,"short_name":"headphones","short_names":["headphones"],"text":null,"texts":null,"category":"Activity","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ARTIST PALETTE","unified":"1F3A8","variations":[],"docomo":"E67B","au":"E59C","softbank":"E502","google":"FE804","image":"1f3a8.png","sheet_x":9,"sheet_y":22,"short_name":"art","short_names":["art"],"text":null,"texts":null,"category":"Activity","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TOP HAT","unified":"1F3A9","variations":[],"docomo":"E67C","au":"EAF5","softbank":"E503","google":"FE805","image":"1f3a9.png","sheet_x":9,"sheet_y":23,"short_name":"tophat","short_names":["tophat"],"text":null,"texts":null,"category":"People","sort_order":192,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CIRCUS TENT","unified":"1F3AA","variations":[],"docomo":"E67D","au":"E59E","softbank":null,"google":"FE806","image":"1f3aa.png","sheet_x":9,"sheet_y":24,"short_name":"circus_tent","short_names":["circus_tent"],"text":null,"texts":null,"category":"Activity","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TICKET","unified":"1F3AB","variations":[],"docomo":"E67E","au":"E49E","softbank":"E125","google":"FE807","image":"1f3ab.png","sheet_x":9,"sheet_y":25,"short_name":"ticket","short_names":["ticket"],"text":null,"texts":null,"category":"Activity","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLAPPER BOARD","unified":"1F3AC","variations":[],"docomo":"E6AC","au":"E4BE","softbank":"E324","google":"FE808","image":"1f3ac.png","sheet_x":9,"sheet_y":26,"short_name":"clapper","short_names":["clapper"],"text":null,"texts":null,"category":"Activity","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PERFORMING ARTS","unified":"1F3AD","variations":[],"docomo":null,"au":"E59D","softbank":"E503","google":"FE809","image":"1f3ad.png","sheet_x":9,"sheet_y":27,"short_name":"performing_arts","short_names":["performing_arts"],"text":null,"texts":null,"category":"Activity","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIDEO GAME","unified":"1F3AE","variations":[],"docomo":"E68B","au":"E4C6","softbank":null,"google":"FE80A","image":"1f3ae.png","sheet_x":9,"sheet_y":28,"short_name":"video_game","short_names":["video_game"],"text":null,"texts":null,"category":"Activity","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DIRECT HIT","unified":"1F3AF","variations":[],"docomo":null,"au":"E4C5","softbank":"E130","google":"FE80C","image":"1f3af.png","sheet_x":9,"sheet_y":29,"short_name":"dart","short_names":["dart"],"text":null,"texts":null,"category":"Activity","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLOT MACHINE","unified":"1F3B0","variations":[],"docomo":null,"au":"E46E","softbank":"E133","google":"FE80D","image":"1f3b0.png","sheet_x":9,"sheet_y":30,"short_name":"slot_machine","short_names":["slot_machine"],"text":null,"texts":null,"category":"Activity","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BILLIARDS","unified":"1F3B1","variations":[],"docomo":null,"au":"EADD","softbank":"E42C","google":"FE80E","image":"1f3b1.png","sheet_x":9,"sheet_y":31,"short_name":"8ball","short_names":["8ball"],"text":null,"texts":null,"category":"Activity","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GAME DIE","unified":"1F3B2","variations":[],"docomo":null,"au":"E4C8","softbank":null,"google":"FE80F","image":"1f3b2.png","sheet_x":9,"sheet_y":32,"short_name":"game_die","short_names":["game_die"],"text":null,"texts":null,"category":"Activity","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOWLING","unified":"1F3B3","variations":[],"docomo":null,"au":"EB43","softbank":null,"google":"FE810","image":"1f3b3.png","sheet_x":9,"sheet_y":33,"short_name":"bowling","short_names":["bowling"],"text":null,"texts":null,"category":"Activity","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLOWER PLAYING CARDS","unified":"1F3B4","variations":[],"docomo":null,"au":"EB6E","softbank":null,"google":"FE811","image":"1f3b4.png","sheet_x":9,"sheet_y":34,"short_name":"flower_playing_cards","short_names":["flower_playing_cards"],"text":null,"texts":null,"category":"Symbols","sort_order":241,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MUSICAL NOTE","unified":"1F3B5","variations":[],"docomo":"E6F6","au":"E5BE","softbank":"E03E","google":"FE813","image":"1f3b5.png","sheet_x":9,"sheet_y":35,"short_name":"musical_note","short_names":["musical_note"],"text":null,"texts":null,"category":"Symbols","sort_order":185,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MULTIPLE MUSICAL NOTES","unified":"1F3B6","variations":[],"docomo":"E6FF","au":"E505","softbank":"E326","google":"FE814","image":"1f3b6.png","sheet_x":9,"sheet_y":36,"short_name":"notes","short_names":["notes"],"text":null,"texts":null,"category":"Symbols","sort_order":186,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SAXOPHONE","unified":"1F3B7","variations":[],"docomo":null,"au":null,"softbank":"E040","google":"FE815","image":"1f3b7.png","sheet_x":9,"sheet_y":37,"short_name":"saxophone","short_names":["saxophone"],"text":null,"texts":null,"category":"Activity","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GUITAR","unified":"1F3B8","variations":[],"docomo":null,"au":"E506","softbank":"E041","google":"FE816","image":"1f3b8.png","sheet_x":9,"sheet_y":38,"short_name":"guitar","short_names":["guitar"],"text":null,"texts":null,"category":"Activity","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MUSICAL KEYBOARD","unified":"1F3B9","variations":[],"docomo":null,"au":"EB40","softbank":null,"google":"FE817","image":"1f3b9.png","sheet_x":9,"sheet_y":39,"short_name":"musical_keyboard","short_names":["musical_keyboard"],"text":null,"texts":null,"category":"Activity","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRUMPET","unified":"1F3BA","variations":[],"docomo":null,"au":"EADC","softbank":"E042","google":"FE818","image":"1f3ba.png","sheet_x":9,"sheet_y":40,"short_name":"trumpet","short_names":["trumpet"],"text":null,"texts":null,"category":"Activity","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIOLIN","unified":"1F3BB","variations":[],"docomo":null,"au":"E507","softbank":null,"google":"FE819","image":"1f3bb.png","sheet_x":10,"sheet_y":0,"short_name":"violin","short_names":["violin"],"text":null,"texts":null,"category":"Activity","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MUSICAL SCORE","unified":"1F3BC","variations":[],"docomo":"E6FF","au":"EACC","softbank":"E326","google":"FE81A","image":"1f3bc.png","sheet_x":10,"sheet_y":1,"short_name":"musical_score","short_names":["musical_score"],"text":null,"texts":null,"category":"Activity","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RUNNING SHIRT WITH SASH","unified":"1F3BD","variations":[],"docomo":"E652","au":null,"softbank":null,"google":"FE7D0","image":"1f3bd.png","sheet_x":10,"sheet_y":2,"short_name":"running_shirt_with_sash","short_names":["running_shirt_with_sash"],"text":null,"texts":null,"category":"Activity","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TENNIS RACQUET AND BALL","unified":"1F3BE","variations":[],"docomo":"E655","au":"E4B7","softbank":"E015","google":"FE7D3","image":"1f3be.png","sheet_x":10,"sheet_y":3,"short_name":"tennis","short_names":["tennis"],"text":null,"texts":null,"category":"Activity","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SKI AND SKI BOOT","unified":"1F3BF","variations":[],"docomo":"E657","au":"EAAC","softbank":"E013","google":"FE7D5","image":"1f3bf.png","sheet_x":10,"sheet_y":4,"short_name":"ski","short_names":["ski"],"text":null,"texts":null,"category":"Activity","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BASKETBALL AND HOOP","unified":"1F3C0","variations":[],"docomo":"E658","au":"E59A","softbank":"E42A","google":"FE7D6","image":"1f3c0.png","sheet_x":10,"sheet_y":5,"short_name":"basketball","short_names":["basketball"],"text":null,"texts":null,"category":"Activity","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHEQUERED FLAG","unified":"1F3C1","variations":[],"docomo":"E659","au":"E4B9","softbank":"E132","google":"FE7D7","image":"1f3c1.png","sheet_x":10,"sheet_y":6,"short_name":"checkered_flag","short_names":["checkered_flag"],"text":null,"texts":null,"category":"Places","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNOWBOARDER","unified":"1F3C2","variations":[],"docomo":"E712","au":"E4B8","softbank":null,"google":"FE7D8","image":"1f3c2.png","sheet_x":10,"sheet_y":7,"short_name":"snowboarder","short_names":["snowboarder"],"text":null,"texts":null,"category":"Activity","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RUNNER","unified":"1F3C3","variations":[],"docomo":"E733","au":"E46B","softbank":"E115","google":"FE7D9","image":"1f3c3.png","sheet_x":10,"sheet_y":8,"short_name":"runner","short_names":["runner","running"],"text":null,"texts":null,"category":"People","sort_order":140,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F3C3-1F3FB":{"unified":"1F3C3-1F3FB","image":"1f3c3-1f3fb.png","sheet_x":10,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C3-1F3FC":{"unified":"1F3C3-1F3FC","image":"1f3c3-1f3fc.png","sheet_x":10,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C3-1F3FD":{"unified":"1F3C3-1F3FD","image":"1f3c3-1f3fd.png","sheet_x":10,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C3-1F3FE":{"unified":"1F3C3-1F3FE","image":"1f3c3-1f3fe.png","sheet_x":10,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C3-1F3FF":{"unified":"1F3C3-1F3FF","image":"1f3c3-1f3ff.png","sheet_x":10,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"SURFER","unified":"1F3C4","variations":[],"docomo":"E712","au":"EB41","softbank":"E017","google":"FE7DA","image":"1f3c4.png","sheet_x":10,"sheet_y":14,"short_name":"surfer","short_names":["surfer"],"text":null,"texts":null,"category":"Activity","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F3C4-1F3FB":{"unified":"1F3C4-1F3FB","image":"1f3c4-1f3fb.png","sheet_x":10,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C4-1F3FC":{"unified":"1F3C4-1F3FC","image":"1f3c4-1f3fc.png","sheet_x":10,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C4-1F3FD":{"unified":"1F3C4-1F3FD","image":"1f3c4-1f3fd.png","sheet_x":10,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C4-1F3FE":{"unified":"1F3C4-1F3FE","image":"1f3c4-1f3fe.png","sheet_x":10,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C4-1F3FF":{"unified":"1F3C4-1F3FF","image":"1f3c4-1f3ff.png","sheet_x":10,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"SPORTS MEDAL","unified":"1F3C5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3c5.png","sheet_x":10,"sheet_y":20,"short_name":"sports_medal","short_names":["sports_medal"],"text":null,"texts":null,"category":"Activity","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TROPHY","unified":"1F3C6","variations":[],"docomo":null,"au":"E5D3","softbank":"E131","google":"FE7DB","image":"1f3c6.png","sheet_x":10,"sheet_y":21,"short_name":"trophy","short_names":["trophy"],"text":null,"texts":null,"category":"Activity","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HORSE RACING","unified":"1F3C7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3c7.png","sheet_x":10,"sheet_y":22,"short_name":"horse_racing","short_names":["horse_racing"],"text":null,"texts":null,"category":"Activity","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F3C7-1F3FB":{"unified":"1F3C7-1F3FB","image":"1f3c7-1f3fb.png","sheet_x":10,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C7-1F3FC":{"unified":"1F3C7-1F3FC","image":"1f3c7-1f3fc.png","sheet_x":10,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C7-1F3FD":{"unified":"1F3C7-1F3FD","image":"1f3c7-1f3fd.png","sheet_x":10,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C7-1F3FE":{"unified":"1F3C7-1F3FE","image":"1f3c7-1f3fe.png","sheet_x":10,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3C7-1F3FF":{"unified":"1F3C7-1F3FF","image":"1f3c7-1f3ff.png","sheet_x":10,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"AMERICAN FOOTBALL","unified":"1F3C8","variations":[],"docomo":null,"au":"E4BB","softbank":"E42B","google":"FE7DD","image":"1f3c8.png","sheet_x":10,"sheet_y":28,"short_name":"football","short_names":["football"],"text":null,"texts":null,"category":"Activity","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RUGBY FOOTBALL","unified":"1F3C9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3c9.png","sheet_x":10,"sheet_y":29,"short_name":"rugby_football","short_names":["rugby_football"],"text":null,"texts":null,"category":"Activity","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SWIMMER","unified":"1F3CA","variations":[],"docomo":null,"au":"EADE","softbank":"E42D","google":"FE7DE","image":"1f3ca.png","sheet_x":10,"sheet_y":30,"short_name":"swimmer","short_names":["swimmer"],"text":null,"texts":null,"category":"Activity","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F3CA-1F3FB":{"unified":"1F3CA-1F3FB","image":"1f3ca-1f3fb.png","sheet_x":10,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CA-1F3FC":{"unified":"1F3CA-1F3FC","image":"1f3ca-1f3fc.png","sheet_x":10,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CA-1F3FD":{"unified":"1F3CA-1F3FD","image":"1f3ca-1f3fd.png","sheet_x":10,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CA-1F3FE":{"unified":"1F3CA-1F3FE","image":"1f3ca-1f3fe.png","sheet_x":10,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CA-1F3FF":{"unified":"1F3CA-1F3FF","image":"1f3ca-1f3ff.png","sheet_x":10,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WEIGHT LIFTER","unified":"1F3CB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3cb.png","sheet_x":10,"sheet_y":36,"short_name":"weight_lifter","short_names":["weight_lifter"],"text":null,"texts":null,"category":"Activity","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F3CB-1F3FB":{"unified":"1F3CB-1F3FB","image":"1f3cb-1f3fb.png","sheet_x":10,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CB-1F3FC":{"unified":"1F3CB-1F3FC","image":"1f3cb-1f3fc.png","sheet_x":10,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CB-1F3FD":{"unified":"1F3CB-1F3FD","image":"1f3cb-1f3fd.png","sheet_x":10,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CB-1F3FE":{"unified":"1F3CB-1F3FE","image":"1f3cb-1f3fe.png","sheet_x":10,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F3CB-1F3FF":{"unified":"1F3CB-1F3FF","image":"1f3cb-1f3ff.png","sheet_x":11,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"GOLFER","unified":"1F3CC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3cc.png","sheet_x":11,"sheet_y":1,"short_name":"golfer","short_names":["golfer"],"text":null,"texts":null,"category":"Activity","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RACING MOTORCYCLE","unified":"1F3CD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3cd.png","sheet_x":11,"sheet_y":2,"short_name":"racing_motorcycle","short_names":["racing_motorcycle"],"text":null,"texts":null,"category":"Places","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RACING CAR","unified":"1F3CE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3ce.png","sheet_x":11,"sheet_y":3,"short_name":"racing_car","short_names":["racing_car"],"text":null,"texts":null,"category":"Places","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CRICKET BAT AND BALL","unified":"1F3CF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3cf.png","sheet_x":11,"sheet_y":4,"short_name":"cricket_bat_and_ball","short_names":["cricket_bat_and_ball"],"text":null,"texts":null,"category":"Activity","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VOLLEYBALL","unified":"1F3D0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d0.png","sheet_x":11,"sheet_y":5,"short_name":"volleyball","short_names":["volleyball"],"text":null,"texts":null,"category":"Activity","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIELD HOCKEY STICK AND BALL","unified":"1F3D1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d1.png","sheet_x":11,"sheet_y":6,"short_name":"field_hockey_stick_and_ball","short_names":["field_hockey_stick_and_ball"],"text":null,"texts":null,"category":"Activity","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ICE HOCKEY STICK AND PUCK","unified":"1F3D2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d2.png","sheet_x":11,"sheet_y":7,"short_name":"ice_hockey_stick_and_puck","short_names":["ice_hockey_stick_and_puck"],"text":null,"texts":null,"category":"Activity","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TABLE TENNIS PADDLE AND BALL","unified":"1F3D3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d3.png","sheet_x":11,"sheet_y":8,"short_name":"table_tennis_paddle_and_ball","short_names":["table_tennis_paddle_and_ball"],"text":null,"texts":null,"category":"Activity","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNOW CAPPED MOUNTAIN","unified":"1F3D4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d4.png","sheet_x":11,"sheet_y":9,"short_name":"snow_capped_mountain","short_names":["snow_capped_mountain"],"text":null,"texts":null,"category":"Places","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAMPING","unified":"1F3D5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d5.png","sheet_x":11,"sheet_y":10,"short_name":"camping","short_names":["camping"],"text":null,"texts":null,"category":"Places","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BEACH WITH UMBRELLA","unified":"1F3D6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d6.png","sheet_x":11,"sheet_y":11,"short_name":"beach_with_umbrella","short_names":["beach_with_umbrella"],"text":null,"texts":null,"category":"Places","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUILDING CONSTRUCTION","unified":"1F3D7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d7.png","sheet_x":11,"sheet_y":12,"short_name":"building_construction","short_names":["building_construction"],"text":null,"texts":null,"category":"Places","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOUSE BUILDINGS","unified":"1F3D8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d8.png","sheet_x":11,"sheet_y":13,"short_name":"house_buildings","short_names":["house_buildings"],"text":null,"texts":null,"category":"Places","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CITYSCAPE","unified":"1F3D9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3d9.png","sheet_x":11,"sheet_y":14,"short_name":"cityscape","short_names":["cityscape"],"text":null,"texts":null,"category":"Places","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DERELICT HOUSE BUILDING","unified":"1F3DA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3da.png","sheet_x":11,"sheet_y":15,"short_name":"derelict_house_building","short_names":["derelict_house_building"],"text":null,"texts":null,"category":"Places","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLASSICAL BUILDING","unified":"1F3DB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3db.png","sheet_x":11,"sheet_y":16,"short_name":"classical_building","short_names":["classical_building"],"text":null,"texts":null,"category":"Places","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DESERT","unified":"1F3DC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3dc.png","sheet_x":11,"sheet_y":17,"short_name":"desert","short_names":["desert"],"text":null,"texts":null,"category":"Places","sort_order":78,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DESERT ISLAND","unified":"1F3DD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3dd.png","sheet_x":11,"sheet_y":18,"short_name":"desert_island","short_names":["desert_island"],"text":null,"texts":null,"category":"Places","sort_order":80,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NATIONAL PARK","unified":"1F3DE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3de.png","sheet_x":11,"sheet_y":19,"short_name":"national_park","short_names":["national_park"],"text":null,"texts":null,"category":"Places","sort_order":73,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STADIUM","unified":"1F3DF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3df.png","sheet_x":11,"sheet_y":20,"short_name":"stadium","short_names":["stadium"],"text":null,"texts":null,"category":"Places","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOUSE BUILDING","unified":"1F3E0","variations":[],"docomo":"E663","au":"E4AB","softbank":"E036","google":"FE4B0","image":"1f3e0.png","sheet_x":11,"sheet_y":21,"short_name":"house","short_names":["house"],"text":null,"texts":null,"category":"Places","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOUSE WITH GARDEN","unified":"1F3E1","variations":[],"docomo":"E663","au":"EB09","softbank":"E036","google":"FE4B1","image":"1f3e1.png","sheet_x":11,"sheet_y":22,"short_name":"house_with_garden","short_names":["house_with_garden"],"text":null,"texts":null,"category":"Places","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OFFICE BUILDING","unified":"1F3E2","variations":[],"docomo":"E664","au":"E4AD","softbank":"E038","google":"FE4B2","image":"1f3e2.png","sheet_x":11,"sheet_y":23,"short_name":"office","short_names":["office"],"text":null,"texts":null,"category":"Places","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JAPANESE POST OFFICE","unified":"1F3E3","variations":[],"docomo":"E665","au":"E5DE","softbank":"E153","google":"FE4B3","image":"1f3e3.png","sheet_x":11,"sheet_y":24,"short_name":"post_office","short_names":["post_office"],"text":null,"texts":null,"category":"Places","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EUROPEAN POST OFFICE","unified":"1F3E4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3e4.png","sheet_x":11,"sheet_y":25,"short_name":"european_post_office","short_names":["european_post_office"],"text":null,"texts":null,"category":"Places","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOSPITAL","unified":"1F3E5","variations":[],"docomo":"E666","au":"E5DF","softbank":"E155","google":"FE4B4","image":"1f3e5.png","sheet_x":11,"sheet_y":26,"short_name":"hospital","short_names":["hospital"],"text":null,"texts":null,"category":"Places","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANK","unified":"1F3E6","variations":[],"docomo":"E667","au":"E4AA","softbank":"E14D","google":"FE4B5","image":"1f3e6.png","sheet_x":11,"sheet_y":27,"short_name":"bank","short_names":["bank"],"text":null,"texts":null,"category":"Places","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AUTOMATED TELLER MACHINE","unified":"1F3E7","variations":[],"docomo":"E668","au":"E4A3","softbank":"E154","google":"FE4B6","image":"1f3e7.png","sheet_x":11,"sheet_y":28,"short_name":"atm","short_names":["atm"],"text":null,"texts":null,"category":"Symbols","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOTEL","unified":"1F3E8","variations":[],"docomo":"E669","au":"EA81","softbank":"E158","google":"FE4B7","image":"1f3e8.png","sheet_x":11,"sheet_y":29,"short_name":"hotel","short_names":["hotel"],"text":null,"texts":null,"category":"Places","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOVE HOTEL","unified":"1F3E9","variations":[],"docomo":"E669-E6EF","au":"EAF3","softbank":"E501","google":"FE4B8","image":"1f3e9.png","sheet_x":11,"sheet_y":30,"short_name":"love_hotel","short_names":["love_hotel"],"text":null,"texts":null,"category":"Places","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONVENIENCE STORE","unified":"1F3EA","variations":[],"docomo":"E66A","au":"E4A4","softbank":"E156","google":"FE4B9","image":"1f3ea.png","sheet_x":11,"sheet_y":31,"short_name":"convenience_store","short_names":["convenience_store"],"text":null,"texts":null,"category":"Places","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCHOOL","unified":"1F3EB","variations":[],"docomo":"E73E","au":"EA80","softbank":"E157","google":"FE4BA","image":"1f3eb.png","sheet_x":11,"sheet_y":32,"short_name":"school","short_names":["school"],"text":null,"texts":null,"category":"Places","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DEPARTMENT STORE","unified":"1F3EC","variations":[],"docomo":null,"au":"EAF6","softbank":"E504","google":"FE4BD","image":"1f3ec.png","sheet_x":11,"sheet_y":33,"short_name":"department_store","short_names":["department_store"],"text":null,"texts":null,"category":"Places","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACTORY","unified":"1F3ED","variations":[],"docomo":null,"au":"EAF9","softbank":"E508","google":"FE4C0","image":"1f3ed.png","sheet_x":11,"sheet_y":34,"short_name":"factory","short_names":["factory"],"text":null,"texts":null,"category":"Places","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"IZAKAYA LANTERN","unified":"1F3EE","variations":[],"docomo":"E74B","au":"E4BD","softbank":"E30B","google":"FE4C2","image":"1f3ee.png","sheet_x":11,"sheet_y":35,"short_name":"izakaya_lantern","short_names":["izakaya_lantern","lantern"],"text":null,"texts":null,"category":"Objects","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JAPANESE CASTLE","unified":"1F3EF","variations":[],"docomo":null,"au":"EAF7","softbank":"E505","google":"FE4BE","image":"1f3ef.png","sheet_x":11,"sheet_y":36,"short_name":"japanese_castle","short_names":["japanese_castle"],"text":null,"texts":null,"category":"Places","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EUROPEAN CASTLE","unified":"1F3F0","variations":[],"docomo":null,"au":"EAF8","softbank":"E506","google":"FE4BF","image":"1f3f0.png","sheet_x":11,"sheet_y":37,"short_name":"european_castle","short_names":["european_castle"],"text":null,"texts":null,"category":"Places","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WAVING WHITE FLAG","unified":"1F3F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f3.png","sheet_x":11,"sheet_y":38,"short_name":"waving_white_flag","short_names":["waving_white_flag"],"text":null,"texts":null,"category":"Objects","sort_order":164,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WAVING BLACK FLAG","unified":"1F3F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f4.png","sheet_x":11,"sheet_y":39,"short_name":"waving_black_flag","short_names":["waving_black_flag"],"text":null,"texts":null,"category":"Objects","sort_order":165,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROSETTE","unified":"1F3F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f5.png","sheet_x":11,"sheet_y":40,"short_name":"rosette","short_names":["rosette"],"text":null,"texts":null,"category":"Activity","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LABEL","unified":"1F3F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f7.png","sheet_x":12,"sheet_y":0,"short_name":"label","short_names":["label"],"text":null,"texts":null,"category":"Objects","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BADMINTON RACQUET AND SHUTTLECOCK","unified":"1F3F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f8.png","sheet_x":12,"sheet_y":1,"short_name":"badminton_racquet_and_shuttlecock","short_names":["badminton_racquet_and_shuttlecock"],"text":null,"texts":null,"category":"Activity","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOW AND ARROW","unified":"1F3F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3f9.png","sheet_x":12,"sheet_y":2,"short_name":"bow_and_arrow","short_names":["bow_and_arrow"],"text":null,"texts":null,"category":"Activity","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AMPHORA","unified":"1F3FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3fa.png","sheet_x":12,"sheet_y":3,"short_name":"amphora","short_names":["amphora"],"text":null,"texts":null,"category":"Objects","sort_order":73,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EMOJI MODIFIER FITZPATRICK TYPE-1-2","unified":"1F3FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3fb.png","sheet_x":12,"sheet_y":4,"short_name":"skin-tone-2","short_names":["skin-tone-2"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"EMOJI MODIFIER FITZPATRICK TYPE-3","unified":"1F3FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3fc.png","sheet_x":12,"sheet_y":5,"short_name":"skin-tone-3","short_names":["skin-tone-3"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"EMOJI MODIFIER FITZPATRICK TYPE-4","unified":"1F3FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3fd.png","sheet_x":12,"sheet_y":6,"short_name":"skin-tone-4","short_names":["skin-tone-4"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"EMOJI MODIFIER FITZPATRICK TYPE-5","unified":"1F3FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3fe.png","sheet_x":12,"sheet_y":7,"short_name":"skin-tone-5","short_names":["skin-tone-5"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"EMOJI MODIFIER FITZPATRICK TYPE-6","unified":"1F3FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f3ff.png","sheet_x":12,"sheet_y":8,"short_name":"skin-tone-6","short_names":["skin-tone-6"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAT","unified":"1F400","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f400.png","sheet_x":12,"sheet_y":9,"short_name":"rat","short_names":["rat"],"text":null,"texts":null,"category":"Nature","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUSE","unified":"1F401","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f401.png","sheet_x":12,"sheet_y":10,"short_name":"mouse2","short_names":["mouse2"],"text":null,"texts":null,"category":"Nature","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OX","unified":"1F402","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f402.png","sheet_x":12,"sheet_y":11,"short_name":"ox","short_names":["ox"],"text":null,"texts":null,"category":"Nature","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WATER BUFFALO","unified":"1F403","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f403.png","sheet_x":12,"sheet_y":12,"short_name":"water_buffalo","short_names":["water_buffalo"],"text":null,"texts":null,"category":"Nature","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COW","unified":"1F404","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f404.png","sheet_x":12,"sheet_y":13,"short_name":"cow2","short_names":["cow2"],"text":null,"texts":null,"category":"Nature","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TIGER","unified":"1F405","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f405.png","sheet_x":12,"sheet_y":14,"short_name":"tiger2","short_names":["tiger2"],"text":null,"texts":null,"category":"Nature","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEOPARD","unified":"1F406","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f406.png","sheet_x":12,"sheet_y":15,"short_name":"leopard","short_names":["leopard"],"text":null,"texts":null,"category":"Nature","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RABBIT","unified":"1F407","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f407.png","sheet_x":12,"sheet_y":16,"short_name":"rabbit2","short_names":["rabbit2"],"text":null,"texts":null,"category":"Nature","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAT","unified":"1F408","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f408.png","sheet_x":12,"sheet_y":17,"short_name":"cat2","short_names":["cat2"],"text":null,"texts":null,"category":"Nature","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DRAGON","unified":"1F409","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f409.png","sheet_x":12,"sheet_y":18,"short_name":"dragon","short_names":["dragon"],"text":null,"texts":null,"category":"Nature","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CROCODILE","unified":"1F40A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f40a.png","sheet_x":12,"sheet_y":19,"short_name":"crocodile","short_names":["crocodile"],"text":null,"texts":null,"category":"Nature","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHALE","unified":"1F40B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f40b.png","sheet_x":12,"sheet_y":20,"short_name":"whale2","short_names":["whale2"],"text":null,"texts":null,"category":"Nature","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNAIL","unified":"1F40C","variations":[],"docomo":"E74E","au":"EB7E","softbank":null,"google":"FE1B9","image":"1f40c.png","sheet_x":12,"sheet_y":21,"short_name":"snail","short_names":["snail"],"text":null,"texts":null,"category":"Nature","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SNAKE","unified":"1F40D","variations":[],"docomo":null,"au":"EB22","softbank":"E52D","google":"FE1D3","image":"1f40d.png","sheet_x":12,"sheet_y":22,"short_name":"snake","short_names":["snake"],"text":null,"texts":null,"category":"Nature","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HORSE","unified":"1F40E","variations":[],"docomo":"E754","au":"E4D8","softbank":"E134","google":"FE7DC","image":"1f40e.png","sheet_x":12,"sheet_y":23,"short_name":"racehorse","short_names":["racehorse"],"text":null,"texts":null,"category":"Nature","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAM","unified":"1F40F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f40f.png","sheet_x":12,"sheet_y":24,"short_name":"ram","short_names":["ram"],"text":null,"texts":null,"category":"Nature","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GOAT","unified":"1F410","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f410.png","sheet_x":12,"sheet_y":25,"short_name":"goat","short_names":["goat"],"text":null,"texts":null,"category":"Nature","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHEEP","unified":"1F411","variations":[],"docomo":null,"au":"E48F","softbank":"E529","google":"FE1CF","image":"1f411.png","sheet_x":12,"sheet_y":26,"short_name":"sheep","short_names":["sheep"],"text":null,"texts":null,"category":"Nature","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONKEY","unified":"1F412","variations":[],"docomo":null,"au":"E4D9","softbank":"E528","google":"FE1CE","image":"1f412.png","sheet_x":12,"sheet_y":27,"short_name":"monkey","short_names":["monkey"],"text":null,"texts":null,"category":"Nature","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROOSTER","unified":"1F413","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f413.png","sheet_x":12,"sheet_y":28,"short_name":"rooster","short_names":["rooster"],"text":null,"texts":null,"category":"Nature","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHICKEN","unified":"1F414","variations":[],"docomo":null,"au":"EB23","softbank":"E52E","google":"FE1D4","image":"1f414.png","sheet_x":12,"sheet_y":29,"short_name":"chicken","short_names":["chicken"],"text":null,"texts":null,"category":"Nature","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOG","unified":"1F415","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f415.png","sheet_x":12,"sheet_y":30,"short_name":"dog2","short_names":["dog2"],"text":null,"texts":null,"category":"Nature","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PIG","unified":"1F416","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f416.png","sheet_x":12,"sheet_y":31,"short_name":"pig2","short_names":["pig2"],"text":null,"texts":null,"category":"Nature","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOAR","unified":"1F417","variations":[],"docomo":null,"au":"EB24","softbank":"E52F","google":"FE1D5","image":"1f417.png","sheet_x":12,"sheet_y":32,"short_name":"boar","short_names":["boar"],"text":null,"texts":null,"category":"Nature","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ELEPHANT","unified":"1F418","variations":[],"docomo":null,"au":"EB1F","softbank":"E526","google":"FE1CC","image":"1f418.png","sheet_x":12,"sheet_y":33,"short_name":"elephant","short_names":["elephant"],"text":null,"texts":null,"category":"Nature","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OCTOPUS","unified":"1F419","variations":[],"docomo":null,"au":"E5C7","softbank":"E10A","google":"FE1C5","image":"1f419.png","sheet_x":12,"sheet_y":34,"short_name":"octopus","short_names":["octopus"],"text":null,"texts":null,"category":"Nature","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPIRAL SHELL","unified":"1F41A","variations":[],"docomo":null,"au":"EAEC","softbank":"E441","google":"FE1C6","image":"1f41a.png","sheet_x":12,"sheet_y":35,"short_name":"shell","short_names":["shell"],"text":null,"texts":null,"category":"Nature","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUG","unified":"1F41B","variations":[],"docomo":null,"au":"EB1E","softbank":"E525","google":"FE1CB","image":"1f41b.png","sheet_x":12,"sheet_y":36,"short_name":"bug","short_names":["bug"],"text":null,"texts":null,"category":"Nature","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANT","unified":"1F41C","variations":[],"docomo":null,"au":"E4DD","softbank":null,"google":"FE1DA","image":"1f41c.png","sheet_x":12,"sheet_y":37,"short_name":"ant","short_names":["ant"],"text":null,"texts":null,"category":"Nature","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HONEYBEE","unified":"1F41D","variations":[],"docomo":null,"au":"EB57","softbank":null,"google":"FE1E1","image":"1f41d.png","sheet_x":12,"sheet_y":38,"short_name":"bee","short_names":["bee","honeybee"],"text":null,"texts":null,"category":"Nature","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LADY BEETLE","unified":"1F41E","variations":[],"docomo":null,"au":"EB58","softbank":null,"google":"FE1E2","image":"1f41e.png","sheet_x":12,"sheet_y":39,"short_name":"beetle","short_names":["beetle"],"text":null,"texts":null,"category":"Nature","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FISH","unified":"1F41F","variations":[],"docomo":"E751","au":"E49A","softbank":"E019","google":"FE1BD","image":"1f41f.png","sheet_x":12,"sheet_y":40,"short_name":"fish","short_names":["fish"],"text":null,"texts":null,"category":"Nature","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TROPICAL FISH","unified":"1F420","variations":[],"docomo":"E751","au":"EB1D","softbank":"E522","google":"FE1C9","image":"1f420.png","sheet_x":13,"sheet_y":0,"short_name":"tropical_fish","short_names":["tropical_fish"],"text":null,"texts":null,"category":"Nature","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLOWFISH","unified":"1F421","variations":[],"docomo":"E751","au":"E4D3","softbank":"E019","google":"FE1D9","image":"1f421.png","sheet_x":13,"sheet_y":1,"short_name":"blowfish","short_names":["blowfish"],"text":null,"texts":null,"category":"Nature","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TURTLE","unified":"1F422","variations":[],"docomo":null,"au":"E5D4","softbank":null,"google":"FE1DC","image":"1f422.png","sheet_x":13,"sheet_y":2,"short_name":"turtle","short_names":["turtle"],"text":null,"texts":null,"category":"Nature","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HATCHING CHICK","unified":"1F423","variations":[],"docomo":"E74F","au":"E5DB","softbank":"E523","google":"FE1DD","image":"1f423.png","sheet_x":13,"sheet_y":3,"short_name":"hatching_chick","short_names":["hatching_chick"],"text":null,"texts":null,"category":"Nature","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BABY CHICK","unified":"1F424","variations":[],"docomo":"E74F","au":"E4E0","softbank":"E523","google":"FE1BA","image":"1f424.png","sheet_x":13,"sheet_y":4,"short_name":"baby_chick","short_names":["baby_chick"],"text":null,"texts":null,"category":"Nature","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FRONT-FACING BABY CHICK","unified":"1F425","variations":[],"docomo":"E74F","au":"EB76","softbank":"E523","google":"FE1BB","image":"1f425.png","sheet_x":13,"sheet_y":5,"short_name":"hatched_chick","short_names":["hatched_chick"],"text":null,"texts":null,"category":"Nature","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BIRD","unified":"1F426","variations":[],"docomo":"E74F","au":"E4E0","softbank":"E521","google":"FE1C8","image":"1f426.png","sheet_x":13,"sheet_y":6,"short_name":"bird","short_names":["bird"],"text":null,"texts":null,"category":"Nature","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PENGUIN","unified":"1F427","variations":[],"docomo":"E750","au":"E4DC","softbank":"E055","google":"FE1BC","image":"1f427.png","sheet_x":13,"sheet_y":7,"short_name":"penguin","short_names":["penguin"],"text":null,"texts":null,"category":"Nature","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KOALA","unified":"1F428","variations":[],"docomo":null,"au":"EB20","softbank":"E527","google":"FE1CD","image":"1f428.png","sheet_x":13,"sheet_y":8,"short_name":"koala","short_names":["koala"],"text":null,"texts":null,"category":"Nature","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POODLE","unified":"1F429","variations":[],"docomo":"E6A1","au":"E4DF","softbank":"E052","google":"FE1D8","image":"1f429.png","sheet_x":13,"sheet_y":9,"short_name":"poodle","short_names":["poodle"],"text":null,"texts":null,"category":"Nature","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DROMEDARY CAMEL","unified":"1F42A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f42a.png","sheet_x":13,"sheet_y":10,"short_name":"dromedary_camel","short_names":["dromedary_camel"],"text":null,"texts":null,"category":"Nature","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BACTRIAN CAMEL","unified":"1F42B","variations":[],"docomo":null,"au":"EB25","softbank":"E530","google":"FE1D6","image":"1f42b.png","sheet_x":13,"sheet_y":11,"short_name":"camel","short_names":["camel"],"text":null,"texts":null,"category":"Nature","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOLPHIN","unified":"1F42C","variations":[],"docomo":null,"au":"EB1B","softbank":"E520","google":"FE1C7","image":"1f42c.png","sheet_x":13,"sheet_y":12,"short_name":"dolphin","short_names":["dolphin","flipper"],"text":null,"texts":null,"category":"Nature","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUSE FACE","unified":"1F42D","variations":[],"docomo":null,"au":"E5C2","softbank":"E053","google":"FE1C2","image":"1f42d.png","sheet_x":13,"sheet_y":13,"short_name":"mouse","short_names":["mouse"],"text":null,"texts":null,"category":"Nature","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COW FACE","unified":"1F42E","variations":[],"docomo":null,"au":"EB21","softbank":"E52B","google":"FE1D1","image":"1f42e.png","sheet_x":13,"sheet_y":14,"short_name":"cow","short_names":["cow"],"text":null,"texts":null,"category":"Nature","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TIGER FACE","unified":"1F42F","variations":[],"docomo":null,"au":"E5C0","softbank":"E050","google":"FE1C0","image":"1f42f.png","sheet_x":13,"sheet_y":15,"short_name":"tiger","short_names":["tiger"],"text":null,"texts":null,"category":"Nature","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RABBIT FACE","unified":"1F430","variations":[],"docomo":null,"au":"E4D7","softbank":"E52C","google":"FE1D2","image":"1f430.png","sheet_x":13,"sheet_y":16,"short_name":"rabbit","short_names":["rabbit"],"text":null,"texts":null,"category":"Nature","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAT FACE","unified":"1F431","variations":[],"docomo":"E6A2","au":"E4DB","softbank":"E04F","google":"FE1B8","image":"1f431.png","sheet_x":13,"sheet_y":17,"short_name":"cat","short_names":["cat"],"text":null,"texts":null,"category":"Nature","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DRAGON FACE","unified":"1F432","variations":[],"docomo":null,"au":"EB3F","softbank":null,"google":"FE1DE","image":"1f432.png","sheet_x":13,"sheet_y":18,"short_name":"dragon_face","short_names":["dragon_face"],"text":null,"texts":null,"category":"Nature","sort_order":73,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPOUTING WHALE","unified":"1F433","variations":[],"docomo":null,"au":"E470","softbank":"E054","google":"FE1C3","image":"1f433.png","sheet_x":13,"sheet_y":19,"short_name":"whale","short_names":["whale"],"text":null,"texts":null,"category":"Nature","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HORSE FACE","unified":"1F434","variations":[],"docomo":"E754","au":"E4D8","softbank":"E01A","google":"FE1BE","image":"1f434.png","sheet_x":13,"sheet_y":20,"short_name":"horse","short_names":["horse"],"text":null,"texts":null,"category":"Nature","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONKEY FACE","unified":"1F435","variations":[],"docomo":null,"au":"E4D9","softbank":"E109","google":"FE1C4","image":"1f435.png","sheet_x":13,"sheet_y":21,"short_name":"monkey_face","short_names":["monkey_face"],"text":null,"texts":[":o)"],"category":"Nature","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOG FACE","unified":"1F436","variations":[],"docomo":"E6A1","au":"E4E1","softbank":"E052","google":"FE1B7","image":"1f436.png","sheet_x":13,"sheet_y":22,"short_name":"dog","short_names":["dog"],"text":null,"texts":null,"category":"Nature","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PIG FACE","unified":"1F437","variations":[],"docomo":"E755","au":"E4DE","softbank":"E10B","google":"FE1BF","image":"1f437.png","sheet_x":13,"sheet_y":23,"short_name":"pig","short_names":["pig"],"text":null,"texts":null,"category":"Nature","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FROG FACE","unified":"1F438","variations":[],"docomo":null,"au":"E4DA","softbank":"E531","google":"FE1D7","image":"1f438.png","sheet_x":13,"sheet_y":24,"short_name":"frog","short_names":["frog"],"text":null,"texts":null,"category":"Nature","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAMSTER FACE","unified":"1F439","variations":[],"docomo":null,"au":null,"softbank":"E524","google":"FE1CA","image":"1f439.png","sheet_x":13,"sheet_y":25,"short_name":"hamster","short_names":["hamster"],"text":null,"texts":null,"category":"Nature","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOLF FACE","unified":"1F43A","variations":[],"docomo":"E6A1","au":"E4E1","softbank":"E52A","google":"FE1D0","image":"1f43a.png","sheet_x":13,"sheet_y":26,"short_name":"wolf","short_names":["wolf"],"text":null,"texts":null,"category":"Nature","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BEAR FACE","unified":"1F43B","variations":[],"docomo":null,"au":"E5C1","softbank":"E051","google":"FE1C1","image":"1f43b.png","sheet_x":13,"sheet_y":27,"short_name":"bear","short_names":["bear"],"text":null,"texts":null,"category":"Nature","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PANDA FACE","unified":"1F43C","variations":[],"docomo":null,"au":"EB46","softbank":null,"google":"FE1DF","image":"1f43c.png","sheet_x":13,"sheet_y":28,"short_name":"panda_face","short_names":["panda_face"],"text":null,"texts":null,"category":"Nature","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PIG NOSE","unified":"1F43D","variations":[],"docomo":"E755","au":"EB48","softbank":"E10B","google":"FE1E0","image":"1f43d.png","sheet_x":13,"sheet_y":29,"short_name":"pig_nose","short_names":["pig_nose"],"text":null,"texts":null,"category":"Nature","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PAW PRINTS","unified":"1F43E","variations":[],"docomo":"E698","au":"E4EE","softbank":"E536","google":"FE1DB","image":"1f43e.png","sheet_x":13,"sheet_y":30,"short_name":"feet","short_names":["feet","paw_prints"],"text":null,"texts":null,"category":"Nature","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHIPMUNK","unified":"1F43F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f43f.png","sheet_x":13,"sheet_y":31,"short_name":"chipmunk","short_names":["chipmunk"],"text":null,"texts":null,"category":"Nature","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EYES","unified":"1F440","variations":[],"docomo":"E691","au":"E5A4","softbank":"E419","google":"FE190","image":"1f440.png","sheet_x":13,"sheet_y":32,"short_name":"eyes","short_names":["eyes"],"text":null,"texts":null,"category":"People","sort_order":117,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EYE","unified":"1F441","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f441.png","sheet_x":13,"sheet_y":33,"short_name":"eye","short_names":["eye"],"text":null,"texts":null,"category":"People","sort_order":116,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EAR","unified":"1F442","variations":[],"docomo":"E692","au":"E5A5","softbank":"E41B","google":"FE191","image":"1f442.png","sheet_x":13,"sheet_y":34,"short_name":"ear","short_names":["ear"],"text":null,"texts":null,"category":"People","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F442-1F3FB":{"unified":"1F442-1F3FB","image":"1f442-1f3fb.png","sheet_x":13,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F442-1F3FC":{"unified":"1F442-1F3FC","image":"1f442-1f3fc.png","sheet_x":13,"sheet_y":36,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F442-1F3FD":{"unified":"1F442-1F3FD","image":"1f442-1f3fd.png","sheet_x":13,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F442-1F3FE":{"unified":"1F442-1F3FE","image":"1f442-1f3fe.png","sheet_x":13,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F442-1F3FF":{"unified":"1F442-1F3FF","image":"1f442-1f3ff.png","sheet_x":13,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"NOSE","unified":"1F443","variations":[],"docomo":null,"au":"EAD0","softbank":"E41A","google":"FE192","image":"1f443.png","sheet_x":13,"sheet_y":40,"short_name":"nose","short_names":["nose"],"text":null,"texts":null,"category":"People","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F443-1F3FB":{"unified":"1F443-1F3FB","image":"1f443-1f3fb.png","sheet_x":14,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F443-1F3FC":{"unified":"1F443-1F3FC","image":"1f443-1f3fc.png","sheet_x":14,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F443-1F3FD":{"unified":"1F443-1F3FD","image":"1f443-1f3fd.png","sheet_x":14,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F443-1F3FE":{"unified":"1F443-1F3FE","image":"1f443-1f3fe.png","sheet_x":14,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F443-1F3FF":{"unified":"1F443-1F3FF","image":"1f443-1f3ff.png","sheet_x":14,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"MOUTH","unified":"1F444","variations":[],"docomo":"E6F9","au":"EAD1","softbank":"E41C","google":"FE193","image":"1f444.png","sheet_x":14,"sheet_y":5,"short_name":"lips","short_names":["lips"],"text":null,"texts":null,"category":"People","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TONGUE","unified":"1F445","variations":[],"docomo":"E728","au":"EB47","softbank":"E409","google":"FE194","image":"1f445.png","sheet_x":14,"sheet_y":6,"short_name":"tongue","short_names":["tongue"],"text":null,"texts":null,"category":"People","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE UP POINTING BACKHAND INDEX","unified":"1F446","variations":[],"docomo":null,"au":"EA8D","softbank":"E22E","google":"FEB99","image":"1f446.png","sheet_x":14,"sheet_y":7,"short_name":"point_up_2","short_names":["point_up_2"],"text":null,"texts":null,"category":"People","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F446-1F3FB":{"unified":"1F446-1F3FB","image":"1f446-1f3fb.png","sheet_x":14,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F446-1F3FC":{"unified":"1F446-1F3FC","image":"1f446-1f3fc.png","sheet_x":14,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F446-1F3FD":{"unified":"1F446-1F3FD","image":"1f446-1f3fd.png","sheet_x":14,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F446-1F3FE":{"unified":"1F446-1F3FE","image":"1f446-1f3fe.png","sheet_x":14,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F446-1F3FF":{"unified":"1F446-1F3FF","image":"1f446-1f3ff.png","sheet_x":14,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WHITE DOWN POINTING BACKHAND INDEX","unified":"1F447","variations":[],"docomo":null,"au":"EA8E","softbank":"E22F","google":"FEB9A","image":"1f447.png","sheet_x":14,"sheet_y":13,"short_name":"point_down","short_names":["point_down"],"text":null,"texts":null,"category":"People","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F447-1F3FB":{"unified":"1F447-1F3FB","image":"1f447-1f3fb.png","sheet_x":14,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F447-1F3FC":{"unified":"1F447-1F3FC","image":"1f447-1f3fc.png","sheet_x":14,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F447-1F3FD":{"unified":"1F447-1F3FD","image":"1f447-1f3fd.png","sheet_x":14,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F447-1F3FE":{"unified":"1F447-1F3FE","image":"1f447-1f3fe.png","sheet_x":14,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F447-1F3FF":{"unified":"1F447-1F3FF","image":"1f447-1f3ff.png","sheet_x":14,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WHITE LEFT POINTING BACKHAND INDEX","unified":"1F448","variations":[],"docomo":null,"au":"E4FF","softbank":"E230","google":"FEB9B","image":"1f448.png","sheet_x":14,"sheet_y":19,"short_name":"point_left","short_names":["point_left"],"text":null,"texts":null,"category":"People","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F448-1F3FB":{"unified":"1F448-1F3FB","image":"1f448-1f3fb.png","sheet_x":14,"sheet_y":20,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F448-1F3FC":{"unified":"1F448-1F3FC","image":"1f448-1f3fc.png","sheet_x":14,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F448-1F3FD":{"unified":"1F448-1F3FD","image":"1f448-1f3fd.png","sheet_x":14,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F448-1F3FE":{"unified":"1F448-1F3FE","image":"1f448-1f3fe.png","sheet_x":14,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F448-1F3FF":{"unified":"1F448-1F3FF","image":"1f448-1f3ff.png","sheet_x":14,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WHITE RIGHT POINTING BACKHAND INDEX","unified":"1F449","variations":[],"docomo":null,"au":"E500","softbank":"E231","google":"FEB9C","image":"1f449.png","sheet_x":14,"sheet_y":25,"short_name":"point_right","short_names":["point_right"],"text":null,"texts":null,"category":"People","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F449-1F3FB":{"unified":"1F449-1F3FB","image":"1f449-1f3fb.png","sheet_x":14,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F449-1F3FC":{"unified":"1F449-1F3FC","image":"1f449-1f3fc.png","sheet_x":14,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F449-1F3FD":{"unified":"1F449-1F3FD","image":"1f449-1f3fd.png","sheet_x":14,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F449-1F3FE":{"unified":"1F449-1F3FE","image":"1f449-1f3fe.png","sheet_x":14,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F449-1F3FF":{"unified":"1F449-1F3FF","image":"1f449-1f3ff.png","sheet_x":14,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"FISTED HAND SIGN","unified":"1F44A","variations":[],"docomo":"E6FD","au":"E4F3","softbank":"E00D","google":"FEB96","image":"1f44a.png","sheet_x":14,"sheet_y":31,"short_name":"facepunch","short_names":["facepunch","punch"],"text":null,"texts":null,"category":"People","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44A-1F3FB":{"unified":"1F44A-1F3FB","image":"1f44a-1f3fb.png","sheet_x":14,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44A-1F3FC":{"unified":"1F44A-1F3FC","image":"1f44a-1f3fc.png","sheet_x":14,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44A-1F3FD":{"unified":"1F44A-1F3FD","image":"1f44a-1f3fd.png","sheet_x":14,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44A-1F3FE":{"unified":"1F44A-1F3FE","image":"1f44a-1f3fe.png","sheet_x":14,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44A-1F3FF":{"unified":"1F44A-1F3FF","image":"1f44a-1f3ff.png","sheet_x":14,"sheet_y":36,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WAVING HAND SIGN","unified":"1F44B","variations":[],"docomo":"E695","au":"EAD6","softbank":"E41E","google":"FEB9D","image":"1f44b.png","sheet_x":14,"sheet_y":37,"short_name":"wave","short_names":["wave"],"text":null,"texts":null,"category":"People","sort_order":90,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44B-1F3FB":{"unified":"1F44B-1F3FB","image":"1f44b-1f3fb.png","sheet_x":14,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44B-1F3FC":{"unified":"1F44B-1F3FC","image":"1f44b-1f3fc.png","sheet_x":14,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44B-1F3FD":{"unified":"1F44B-1F3FD","image":"1f44b-1f3fd.png","sheet_x":14,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44B-1F3FE":{"unified":"1F44B-1F3FE","image":"1f44b-1f3fe.png","sheet_x":15,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44B-1F3FF":{"unified":"1F44B-1F3FF","image":"1f44b-1f3ff.png","sheet_x":15,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"OK HAND SIGN","unified":"1F44C","variations":[],"docomo":"E70B","au":"EAD4","softbank":"E420","google":"FEB9F","image":"1f44c.png","sheet_x":15,"sheet_y":2,"short_name":"ok_hand","short_names":["ok_hand"],"text":null,"texts":null,"category":"People","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44C-1F3FB":{"unified":"1F44C-1F3FB","image":"1f44c-1f3fb.png","sheet_x":15,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44C-1F3FC":{"unified":"1F44C-1F3FC","image":"1f44c-1f3fc.png","sheet_x":15,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44C-1F3FD":{"unified":"1F44C-1F3FD","image":"1f44c-1f3fd.png","sheet_x":15,"sheet_y":5,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44C-1F3FE":{"unified":"1F44C-1F3FE","image":"1f44c-1f3fe.png","sheet_x":15,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44C-1F3FF":{"unified":"1F44C-1F3FF","image":"1f44c-1f3ff.png","sheet_x":15,"sheet_y":7,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"THUMBS UP SIGN","unified":"1F44D","variations":[],"docomo":"E727","au":"E4F9","softbank":"E00E","google":"FEB97","image":"1f44d.png","sheet_x":15,"sheet_y":8,"short_name":"+1","short_names":["+1","thumbsup"],"text":null,"texts":null,"category":"People","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44D-1F3FB":{"unified":"1F44D-1F3FB","image":"1f44d-1f3fb.png","sheet_x":15,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44D-1F3FC":{"unified":"1F44D-1F3FC","image":"1f44d-1f3fc.png","sheet_x":15,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44D-1F3FD":{"unified":"1F44D-1F3FD","image":"1f44d-1f3fd.png","sheet_x":15,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44D-1F3FE":{"unified":"1F44D-1F3FE","image":"1f44d-1f3fe.png","sheet_x":15,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44D-1F3FF":{"unified":"1F44D-1F3FF","image":"1f44d-1f3ff.png","sheet_x":15,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"THUMBS DOWN SIGN","unified":"1F44E","variations":[],"docomo":"E700","au":"EAD5","softbank":"E421","google":"FEBA0","image":"1f44e.png","sheet_x":15,"sheet_y":14,"short_name":"-1","short_names":["-1","thumbsdown"],"text":null,"texts":null,"category":"People","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44E-1F3FB":{"unified":"1F44E-1F3FB","image":"1f44e-1f3fb.png","sheet_x":15,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44E-1F3FC":{"unified":"1F44E-1F3FC","image":"1f44e-1f3fc.png","sheet_x":15,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44E-1F3FD":{"unified":"1F44E-1F3FD","image":"1f44e-1f3fd.png","sheet_x":15,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44E-1F3FE":{"unified":"1F44E-1F3FE","image":"1f44e-1f3fe.png","sheet_x":15,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44E-1F3FF":{"unified":"1F44E-1F3FF","image":"1f44e-1f3ff.png","sheet_x":15,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"CLAPPING HANDS SIGN","unified":"1F44F","variations":[],"docomo":null,"au":"EAD3","softbank":"E41F","google":"FEB9E","image":"1f44f.png","sheet_x":15,"sheet_y":20,"short_name":"clap","short_names":["clap"],"text":null,"texts":null,"category":"People","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F44F-1F3FB":{"unified":"1F44F-1F3FB","image":"1f44f-1f3fb.png","sheet_x":15,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44F-1F3FC":{"unified":"1F44F-1F3FC","image":"1f44f-1f3fc.png","sheet_x":15,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44F-1F3FD":{"unified":"1F44F-1F3FD","image":"1f44f-1f3fd.png","sheet_x":15,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44F-1F3FE":{"unified":"1F44F-1F3FE","image":"1f44f-1f3fe.png","sheet_x":15,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F44F-1F3FF":{"unified":"1F44F-1F3FF","image":"1f44f-1f3ff.png","sheet_x":15,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"OPEN HANDS SIGN","unified":"1F450","variations":[],"docomo":"E695","au":"EAD6","softbank":"E422","google":"FEBA1","image":"1f450.png","sheet_x":15,"sheet_y":26,"short_name":"open_hands","short_names":["open_hands"],"text":null,"texts":null,"category":"People","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F450-1F3FB":{"unified":"1F450-1F3FB","image":"1f450-1f3fb.png","sheet_x":15,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F450-1F3FC":{"unified":"1F450-1F3FC","image":"1f450-1f3fc.png","sheet_x":15,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F450-1F3FD":{"unified":"1F450-1F3FD","image":"1f450-1f3fd.png","sheet_x":15,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F450-1F3FE":{"unified":"1F450-1F3FE","image":"1f450-1f3fe.png","sheet_x":15,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F450-1F3FF":{"unified":"1F450-1F3FF","image":"1f450-1f3ff.png","sheet_x":15,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"CROWN","unified":"1F451","variations":[],"docomo":"E71A","au":"E5C9","softbank":"E10E","google":"FE4D1","image":"1f451.png","sheet_x":15,"sheet_y":32,"short_name":"crown","short_names":["crown"],"text":null,"texts":null,"category":"People","sort_order":195,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOMANS HAT","unified":"1F452","variations":[],"docomo":null,"au":"EA9E","softbank":"E318","google":"FE4D4","image":"1f452.png","sheet_x":15,"sheet_y":33,"short_name":"womans_hat","short_names":["womans_hat"],"text":null,"texts":null,"category":"People","sort_order":191,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EYEGLASSES","unified":"1F453","variations":[],"docomo":"E69A","au":"E4FE","softbank":null,"google":"FE4CE","image":"1f453.png","sheet_x":15,"sheet_y":34,"short_name":"eyeglasses","short_names":["eyeglasses"],"text":null,"texts":null,"category":"People","sort_order":201,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NECKTIE","unified":"1F454","variations":[],"docomo":null,"au":"EA93","softbank":"E302","google":"FE4D3","image":"1f454.png","sheet_x":15,"sheet_y":35,"short_name":"necktie","short_names":["necktie"],"text":null,"texts":null,"category":"People","sort_order":179,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"T-SHIRT","unified":"1F455","variations":[],"docomo":"E70E","au":"E5B6","softbank":"E006","google":"FE4CF","image":"1f455.png","sheet_x":15,"sheet_y":36,"short_name":"shirt","short_names":["shirt","tshirt"],"text":null,"texts":null,"category":"People","sort_order":177,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JEANS","unified":"1F456","variations":[],"docomo":"E711","au":"EB77","softbank":null,"google":"FE4D0","image":"1f456.png","sheet_x":15,"sheet_y":37,"short_name":"jeans","short_names":["jeans"],"text":null,"texts":null,"category":"People","sort_order":178,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DRESS","unified":"1F457","variations":[],"docomo":null,"au":"EB6B","softbank":"E319","google":"FE4D5","image":"1f457.png","sheet_x":15,"sheet_y":38,"short_name":"dress","short_names":["dress"],"text":null,"texts":null,"category":"People","sort_order":180,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KIMONO","unified":"1F458","variations":[],"docomo":null,"au":"EAA3","softbank":"E321","google":"FE4D9","image":"1f458.png","sheet_x":15,"sheet_y":39,"short_name":"kimono","short_names":["kimono"],"text":null,"texts":null,"category":"People","sort_order":182,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BIKINI","unified":"1F459","variations":[],"docomo":null,"au":"EAA4","softbank":"E322","google":"FE4DA","image":"1f459.png","sheet_x":15,"sheet_y":40,"short_name":"bikini","short_names":["bikini"],"text":null,"texts":null,"category":"People","sort_order":181,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOMANS CLOTHES","unified":"1F45A","variations":[],"docomo":"E70E","au":"E50D","softbank":"E006","google":"FE4DB","image":"1f45a.png","sheet_x":16,"sheet_y":0,"short_name":"womans_clothes","short_names":["womans_clothes"],"text":null,"texts":null,"category":"People","sort_order":176,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PURSE","unified":"1F45B","variations":[],"docomo":"E70F","au":"E504","softbank":null,"google":"FE4DC","image":"1f45b.png","sheet_x":16,"sheet_y":1,"short_name":"purse","short_names":["purse"],"text":null,"texts":null,"category":"People","sort_order":198,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HANDBAG","unified":"1F45C","variations":[],"docomo":"E682","au":"E49C","softbank":"E323","google":"FE4F0","image":"1f45c.png","sheet_x":16,"sheet_y":2,"short_name":"handbag","short_names":["handbag"],"text":null,"texts":null,"category":"People","sort_order":199,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POUCH","unified":"1F45D","variations":[],"docomo":"E6AD","au":null,"softbank":null,"google":"FE4F1","image":"1f45d.png","sheet_x":16,"sheet_y":3,"short_name":"pouch","short_names":["pouch"],"text":null,"texts":null,"category":"People","sort_order":197,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MANS SHOE","unified":"1F45E","variations":[],"docomo":"E699","au":"E5B7","softbank":"E007","google":"FE4CC","image":"1f45e.png","sheet_x":16,"sheet_y":4,"short_name":"mans_shoe","short_names":["mans_shoe","shoe"],"text":null,"texts":null,"category":"People","sort_order":189,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ATHLETIC SHOE","unified":"1F45F","variations":[],"docomo":"E699","au":"EB2B","softbank":"E007","google":"FE4CD","image":"1f45f.png","sheet_x":16,"sheet_y":5,"short_name":"athletic_shoe","short_names":["athletic_shoe"],"text":null,"texts":null,"category":"People","sort_order":190,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIGH-HEELED SHOE","unified":"1F460","variations":[],"docomo":"E674","au":"E51A","softbank":"E13E","google":"FE4D6","image":"1f460.png","sheet_x":16,"sheet_y":6,"short_name":"high_heel","short_names":["high_heel"],"text":null,"texts":null,"category":"People","sort_order":186,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOMANS SANDAL","unified":"1F461","variations":[],"docomo":"E674","au":"E51A","softbank":"E31A","google":"FE4D7","image":"1f461.png","sheet_x":16,"sheet_y":7,"short_name":"sandal","short_names":["sandal"],"text":null,"texts":null,"category":"People","sort_order":187,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOMANS BOOTS","unified":"1F462","variations":[],"docomo":null,"au":"EA9F","softbank":"E31B","google":"FE4D8","image":"1f462.png","sheet_x":16,"sheet_y":8,"short_name":"boot","short_names":["boot"],"text":null,"texts":null,"category":"People","sort_order":188,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FOOTPRINTS","unified":"1F463","variations":[],"docomo":"E698","au":"EB2A","softbank":"E536","google":"FE553","image":"1f463.png","sheet_x":16,"sheet_y":9,"short_name":"footprints","short_names":["footprints"],"text":null,"texts":null,"category":"People","sort_order":185,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUST IN SILHOUETTE","unified":"1F464","variations":[],"docomo":"E6B1","au":null,"softbank":null,"google":"FE19A","image":"1f464.png","sheet_x":16,"sheet_y":10,"short_name":"bust_in_silhouette","short_names":["bust_in_silhouette"],"text":null,"texts":null,"category":"People","sort_order":118,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUSTS IN SILHOUETTE","unified":"1F465","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f465.png","sheet_x":16,"sheet_y":11,"short_name":"busts_in_silhouette","short_names":["busts_in_silhouette"],"text":null,"texts":null,"category":"People","sort_order":119,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOY","unified":"1F466","variations":[],"docomo":"E6F0","au":"E4FC","softbank":"E001","google":"FE19B","image":"1f466.png","sheet_x":16,"sheet_y":12,"short_name":"boy","short_names":["boy"],"text":null,"texts":null,"category":"People","sort_order":122,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F466-1F3FB":{"unified":"1F466-1F3FB","image":"1f466-1f3fb.png","sheet_x":16,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F466-1F3FC":{"unified":"1F466-1F3FC","image":"1f466-1f3fc.png","sheet_x":16,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F466-1F3FD":{"unified":"1F466-1F3FD","image":"1f466-1f3fd.png","sheet_x":16,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F466-1F3FE":{"unified":"1F466-1F3FE","image":"1f466-1f3fe.png","sheet_x":16,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F466-1F3FF":{"unified":"1F466-1F3FF","image":"1f466-1f3ff.png","sheet_x":16,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"GIRL","unified":"1F467","variations":[],"docomo":"E6F0","au":"E4FA","softbank":"E002","google":"FE19C","image":"1f467.png","sheet_x":16,"sheet_y":18,"short_name":"girl","short_names":["girl"],"text":null,"texts":null,"category":"People","sort_order":123,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F467-1F3FB":{"unified":"1F467-1F3FB","image":"1f467-1f3fb.png","sheet_x":16,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F467-1F3FC":{"unified":"1F467-1F3FC","image":"1f467-1f3fc.png","sheet_x":16,"sheet_y":20,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F467-1F3FD":{"unified":"1F467-1F3FD","image":"1f467-1f3fd.png","sheet_x":16,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F467-1F3FE":{"unified":"1F467-1F3FE","image":"1f467-1f3fe.png","sheet_x":16,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F467-1F3FF":{"unified":"1F467-1F3FF","image":"1f467-1f3ff.png","sheet_x":16,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"MAN","unified":"1F468","variations":[],"docomo":"E6F0","au":"E4FC","softbank":"E004","google":"FE19D","image":"1f468.png","sheet_x":16,"sheet_y":24,"short_name":"man","short_names":["man"],"text":null,"texts":null,"category":"People","sort_order":124,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F468-1F3FB":{"unified":"1F468-1F3FB","image":"1f468-1f3fb.png","sheet_x":16,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F468-1F3FC":{"unified":"1F468-1F3FC","image":"1f468-1f3fc.png","sheet_x":16,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F468-1F3FD":{"unified":"1F468-1F3FD","image":"1f468-1f3fd.png","sheet_x":16,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F468-1F3FE":{"unified":"1F468-1F3FE","image":"1f468-1f3fe.png","sheet_x":16,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F468-1F3FF":{"unified":"1F468-1F3FF","image":"1f468-1f3ff.png","sheet_x":16,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WOMAN","unified":"1F469","variations":[],"docomo":"E6F0","au":"E4FA","softbank":"E005","google":"FE19E","image":"1f469.png","sheet_x":16,"sheet_y":30,"short_name":"woman","short_names":["woman"],"text":null,"texts":null,"category":"People","sort_order":125,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F469-1F3FB":{"unified":"1F469-1F3FB","image":"1f469-1f3fb.png","sheet_x":16,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F469-1F3FC":{"unified":"1F469-1F3FC","image":"1f469-1f3fc.png","sheet_x":16,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F469-1F3FD":{"unified":"1F469-1F3FD","image":"1f469-1f3fd.png","sheet_x":16,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F469-1F3FE":{"unified":"1F469-1F3FE","image":"1f469-1f3fe.png","sheet_x":16,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F469-1F3FF":{"unified":"1F469-1F3FF","image":"1f469-1f3ff.png","sheet_x":16,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"FAMILY","unified":"1F46A","variations":["1F468-200D-1F469-200D-1F466"],"docomo":null,"au":"E501","softbank":null,"google":"FE19F","image":"1f46a.png","sheet_x":16,"sheet_y":36,"short_name":"family","short_names":["family","man-woman-boy"],"text":null,"texts":null,"category":"People","sort_order":161,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MAN AND WOMAN HOLDING HANDS","unified":"1F46B","variations":[],"docomo":null,"au":null,"softbank":"E428","google":"FE1A0","image":"1f46b.png","sheet_x":16,"sheet_y":37,"short_name":"couple","short_names":["couple","man_and_woman_holding_hands"],"text":null,"texts":null,"category":"People","sort_order":143,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TWO MEN HOLDING HANDS","unified":"1F46C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f46c.png","sheet_x":16,"sheet_y":38,"short_name":"two_men_holding_hands","short_names":["two_men_holding_hands"],"text":null,"texts":null,"category":"People","sort_order":144,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TWO WOMEN HOLDING HANDS","unified":"1F46D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f46d.png","sheet_x":16,"sheet_y":39,"short_name":"two_women_holding_hands","short_names":["two_women_holding_hands"],"text":null,"texts":null,"category":"People","sort_order":145,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POLICE OFFICER","unified":"1F46E","variations":[],"docomo":null,"au":"E5DD","softbank":"E152","google":"FE1A1","image":"1f46e.png","sheet_x":16,"sheet_y":40,"short_name":"cop","short_names":["cop"],"text":null,"texts":null,"category":"People","sort_order":131,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F46E-1F3FB":{"unified":"1F46E-1F3FB","image":"1f46e-1f3fb.png","sheet_x":17,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F46E-1F3FC":{"unified":"1F46E-1F3FC","image":"1f46e-1f3fc.png","sheet_x":17,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F46E-1F3FD":{"unified":"1F46E-1F3FD","image":"1f46e-1f3fd.png","sheet_x":17,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F46E-1F3FE":{"unified":"1F46E-1F3FE","image":"1f46e-1f3fe.png","sheet_x":17,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F46E-1F3FF":{"unified":"1F46E-1F3FF","image":"1f46e-1f3ff.png","sheet_x":17,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"WOMAN WITH BUNNY EARS","unified":"1F46F","variations":[],"docomo":null,"au":"EADB","softbank":"E429","google":"FE1A2","image":"1f46f.png","sheet_x":17,"sheet_y":5,"short_name":"dancers","short_names":["dancers"],"text":null,"texts":null,"category":"People","sort_order":142,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BRIDE WITH VEIL","unified":"1F470","variations":[],"docomo":null,"au":"EAE9","softbank":null,"google":"FE1A3","image":"1f470.png","sheet_x":17,"sheet_y":6,"short_name":"bride_with_veil","short_names":["bride_with_veil"],"text":null,"texts":null,"category":"People","sort_order":138,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F470-1F3FB":{"unified":"1F470-1F3FB","image":"1f470-1f3fb.png","sheet_x":17,"sheet_y":7,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F470-1F3FC":{"unified":"1F470-1F3FC","image":"1f470-1f3fc.png","sheet_x":17,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F470-1F3FD":{"unified":"1F470-1F3FD","image":"1f470-1f3fd.png","sheet_x":17,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F470-1F3FE":{"unified":"1F470-1F3FE","image":"1f470-1f3fe.png","sheet_x":17,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F470-1F3FF":{"unified":"1F470-1F3FF","image":"1f470-1f3ff.png","sheet_x":17,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON WITH BLOND HAIR","unified":"1F471","variations":[],"docomo":null,"au":"EB13","softbank":"E515","google":"FE1A4","image":"1f471.png","sheet_x":17,"sheet_y":12,"short_name":"person_with_blond_hair","short_names":["person_with_blond_hair"],"text":null,"texts":null,"category":"People","sort_order":126,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F471-1F3FB":{"unified":"1F471-1F3FB","image":"1f471-1f3fb.png","sheet_x":17,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F471-1F3FC":{"unified":"1F471-1F3FC","image":"1f471-1f3fc.png","sheet_x":17,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F471-1F3FD":{"unified":"1F471-1F3FD","image":"1f471-1f3fd.png","sheet_x":17,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F471-1F3FE":{"unified":"1F471-1F3FE","image":"1f471-1f3fe.png","sheet_x":17,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F471-1F3FF":{"unified":"1F471-1F3FF","image":"1f471-1f3ff.png","sheet_x":17,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"MAN WITH GUA PI MAO","unified":"1F472","variations":[],"docomo":null,"au":"EB14","softbank":"E516","google":"FE1A5","image":"1f472.png","sheet_x":17,"sheet_y":18,"short_name":"man_with_gua_pi_mao","short_names":["man_with_gua_pi_mao"],"text":null,"texts":null,"category":"People","sort_order":129,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F472-1F3FB":{"unified":"1F472-1F3FB","image":"1f472-1f3fb.png","sheet_x":17,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F472-1F3FC":{"unified":"1F472-1F3FC","image":"1f472-1f3fc.png","sheet_x":17,"sheet_y":20,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F472-1F3FD":{"unified":"1F472-1F3FD","image":"1f472-1f3fd.png","sheet_x":17,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F472-1F3FE":{"unified":"1F472-1F3FE","image":"1f472-1f3fe.png","sheet_x":17,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F472-1F3FF":{"unified":"1F472-1F3FF","image":"1f472-1f3ff.png","sheet_x":17,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"MAN WITH TURBAN","unified":"1F473","variations":[],"docomo":null,"au":"EB15","softbank":"E517","google":"FE1A6","image":"1f473.png","sheet_x":17,"sheet_y":24,"short_name":"man_with_turban","short_names":["man_with_turban"],"text":null,"texts":null,"category":"People","sort_order":130,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F473-1F3FB":{"unified":"1F473-1F3FB","image":"1f473-1f3fb.png","sheet_x":17,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F473-1F3FC":{"unified":"1F473-1F3FC","image":"1f473-1f3fc.png","sheet_x":17,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F473-1F3FD":{"unified":"1F473-1F3FD","image":"1f473-1f3fd.png","sheet_x":17,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F473-1F3FE":{"unified":"1F473-1F3FE","image":"1f473-1f3fe.png","sheet_x":17,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F473-1F3FF":{"unified":"1F473-1F3FF","image":"1f473-1f3ff.png","sheet_x":17,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"OLDER MAN","unified":"1F474","variations":[],"docomo":null,"au":"EB16","softbank":"E518","google":"FE1A7","image":"1f474.png","sheet_x":17,"sheet_y":30,"short_name":"older_man","short_names":["older_man"],"text":null,"texts":null,"category":"People","sort_order":127,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F474-1F3FB":{"unified":"1F474-1F3FB","image":"1f474-1f3fb.png","sheet_x":17,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F474-1F3FC":{"unified":"1F474-1F3FC","image":"1f474-1f3fc.png","sheet_x":17,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F474-1F3FD":{"unified":"1F474-1F3FD","image":"1f474-1f3fd.png","sheet_x":17,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F474-1F3FE":{"unified":"1F474-1F3FE","image":"1f474-1f3fe.png","sheet_x":17,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F474-1F3FF":{"unified":"1F474-1F3FF","image":"1f474-1f3ff.png","sheet_x":17,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"OLDER WOMAN","unified":"1F475","variations":[],"docomo":null,"au":"EB17","softbank":"E519","google":"FE1A8","image":"1f475.png","sheet_x":17,"sheet_y":36,"short_name":"older_woman","short_names":["older_woman"],"text":null,"texts":null,"category":"People","sort_order":128,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F475-1F3FB":{"unified":"1F475-1F3FB","image":"1f475-1f3fb.png","sheet_x":17,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F475-1F3FC":{"unified":"1F475-1F3FC","image":"1f475-1f3fc.png","sheet_x":17,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F475-1F3FD":{"unified":"1F475-1F3FD","image":"1f475-1f3fd.png","sheet_x":17,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F475-1F3FE":{"unified":"1F475-1F3FE","image":"1f475-1f3fe.png","sheet_x":17,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F475-1F3FF":{"unified":"1F475-1F3FF","image":"1f475-1f3ff.png","sheet_x":18,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"BABY","unified":"1F476","variations":[],"docomo":null,"au":"EB18","softbank":"E51A","google":"FE1A9","image":"1f476.png","sheet_x":18,"sheet_y":1,"short_name":"baby","short_names":["baby"],"text":null,"texts":null,"category":"People","sort_order":121,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F476-1F3FB":{"unified":"1F476-1F3FB","image":"1f476-1f3fb.png","sheet_x":18,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F476-1F3FC":{"unified":"1F476-1F3FC","image":"1f476-1f3fc.png","sheet_x":18,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F476-1F3FD":{"unified":"1F476-1F3FD","image":"1f476-1f3fd.png","sheet_x":18,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F476-1F3FE":{"unified":"1F476-1F3FE","image":"1f476-1f3fe.png","sheet_x":18,"sheet_y":5,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F476-1F3FF":{"unified":"1F476-1F3FF","image":"1f476-1f3ff.png","sheet_x":18,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"CONSTRUCTION WORKER","unified":"1F477","variations":[],"docomo":null,"au":"EB19","softbank":"E51B","google":"FE1AA","image":"1f477.png","sheet_x":18,"sheet_y":7,"short_name":"construction_worker","short_names":["construction_worker"],"text":null,"texts":null,"category":"People","sort_order":132,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F477-1F3FB":{"unified":"1F477-1F3FB","image":"1f477-1f3fb.png","sheet_x":18,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F477-1F3FC":{"unified":"1F477-1F3FC","image":"1f477-1f3fc.png","sheet_x":18,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F477-1F3FD":{"unified":"1F477-1F3FD","image":"1f477-1f3fd.png","sheet_x":18,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F477-1F3FE":{"unified":"1F477-1F3FE","image":"1f477-1f3fe.png","sheet_x":18,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F477-1F3FF":{"unified":"1F477-1F3FF","image":"1f477-1f3ff.png","sheet_x":18,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PRINCESS","unified":"1F478","variations":[],"docomo":null,"au":"EB1A","softbank":"E51C","google":"FE1AB","image":"1f478.png","sheet_x":18,"sheet_y":13,"short_name":"princess","short_names":["princess"],"text":null,"texts":null,"category":"People","sort_order":137,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F478-1F3FB":{"unified":"1F478-1F3FB","image":"1f478-1f3fb.png","sheet_x":18,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F478-1F3FC":{"unified":"1F478-1F3FC","image":"1f478-1f3fc.png","sheet_x":18,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F478-1F3FD":{"unified":"1F478-1F3FD","image":"1f478-1f3fd.png","sheet_x":18,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F478-1F3FE":{"unified":"1F478-1F3FE","image":"1f478-1f3fe.png","sheet_x":18,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F478-1F3FF":{"unified":"1F478-1F3FF","image":"1f478-1f3ff.png","sheet_x":18,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"JAPANESE OGRE","unified":"1F479","variations":[],"docomo":null,"au":"EB44","softbank":null,"google":"FE1AC","image":"1f479.png","sheet_x":18,"sheet_y":19,"short_name":"japanese_ogre","short_names":["japanese_ogre"],"text":null,"texts":null,"category":"People","sort_order":73,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JAPANESE GOBLIN","unified":"1F47A","variations":[],"docomo":null,"au":"EB45","softbank":null,"google":"FE1AD","image":"1f47a.png","sheet_x":18,"sheet_y":20,"short_name":"japanese_goblin","short_names":["japanese_goblin"],"text":null,"texts":null,"category":"People","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GHOST","unified":"1F47B","variations":[],"docomo":null,"au":"E4CB","softbank":"E11B","google":"FE1AE","image":"1f47b.png","sheet_x":18,"sheet_y":21,"short_name":"ghost","short_names":["ghost"],"text":null,"texts":null,"category":"People","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BABY ANGEL","unified":"1F47C","variations":[],"docomo":null,"au":"E5BF","softbank":"E04E","google":"FE1AF","image":"1f47c.png","sheet_x":18,"sheet_y":22,"short_name":"angel","short_names":["angel"],"text":null,"texts":null,"category":"People","sort_order":136,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F47C-1F3FB":{"unified":"1F47C-1F3FB","image":"1f47c-1f3fb.png","sheet_x":18,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F47C-1F3FC":{"unified":"1F47C-1F3FC","image":"1f47c-1f3fc.png","sheet_x":18,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F47C-1F3FD":{"unified":"1F47C-1F3FD","image":"1f47c-1f3fd.png","sheet_x":18,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F47C-1F3FE":{"unified":"1F47C-1F3FE","image":"1f47c-1f3fe.png","sheet_x":18,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F47C-1F3FF":{"unified":"1F47C-1F3FF","image":"1f47c-1f3ff.png","sheet_x":18,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"EXTRATERRESTRIAL ALIEN","unified":"1F47D","variations":[],"docomo":null,"au":"E50E","softbank":"E10C","google":"FE1B0","image":"1f47d.png","sheet_x":18,"sheet_y":28,"short_name":"alien","short_names":["alien"],"text":null,"texts":null,"category":"People","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ALIEN MONSTER","unified":"1F47E","variations":[],"docomo":null,"au":"E4EC","softbank":"E12B","google":"FE1B1","image":"1f47e.png","sheet_x":18,"sheet_y":29,"short_name":"space_invader","short_names":["space_invader"],"text":null,"texts":null,"category":"Activity","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"IMP","unified":"1F47F","variations":[],"docomo":null,"au":"E4EF","softbank":"E11A","google":"FE1B2","image":"1f47f.png","sheet_x":18,"sheet_y":30,"short_name":"imp","short_names":["imp"],"text":null,"texts":null,"category":"People","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SKULL","unified":"1F480","variations":[],"docomo":null,"au":"E4F8","softbank":"E11C","google":"FE1B3","image":"1f480.png","sheet_x":18,"sheet_y":31,"short_name":"skull","short_names":["skull"],"text":null,"texts":null,"category":"People","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INFORMATION DESK PERSON","unified":"1F481","variations":[],"docomo":null,"au":null,"softbank":"E253","google":"FE1B4","image":"1f481.png","sheet_x":18,"sheet_y":32,"short_name":"information_desk_person","short_names":["information_desk_person"],"text":null,"texts":null,"category":"People","sort_order":147,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F481-1F3FB":{"unified":"1F481-1F3FB","image":"1f481-1f3fb.png","sheet_x":18,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F481-1F3FC":{"unified":"1F481-1F3FC","image":"1f481-1f3fc.png","sheet_x":18,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F481-1F3FD":{"unified":"1F481-1F3FD","image":"1f481-1f3fd.png","sheet_x":18,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F481-1F3FE":{"unified":"1F481-1F3FE","image":"1f481-1f3fe.png","sheet_x":18,"sheet_y":36,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F481-1F3FF":{"unified":"1F481-1F3FF","image":"1f481-1f3ff.png","sheet_x":18,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"GUARDSMAN","unified":"1F482","variations":[],"docomo":null,"au":null,"softbank":"E51E","google":"FE1B5","image":"1f482.png","sheet_x":18,"sheet_y":38,"short_name":"guardsman","short_names":["guardsman"],"text":null,"texts":null,"category":"People","sort_order":133,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F482-1F3FB":{"unified":"1F482-1F3FB","image":"1f482-1f3fb.png","sheet_x":18,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F482-1F3FC":{"unified":"1F482-1F3FC","image":"1f482-1f3fc.png","sheet_x":18,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F482-1F3FD":{"unified":"1F482-1F3FD","image":"1f482-1f3fd.png","sheet_x":19,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F482-1F3FE":{"unified":"1F482-1F3FE","image":"1f482-1f3fe.png","sheet_x":19,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F482-1F3FF":{"unified":"1F482-1F3FF","image":"1f482-1f3ff.png","sheet_x":19,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"DANCER","unified":"1F483","variations":[],"docomo":null,"au":"EB1C","softbank":"E51F","google":"FE1B6","image":"1f483.png","sheet_x":19,"sheet_y":3,"short_name":"dancer","short_names":["dancer"],"text":null,"texts":null,"category":"People","sort_order":141,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F483-1F3FB":{"unified":"1F483-1F3FB","image":"1f483-1f3fb.png","sheet_x":19,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F483-1F3FC":{"unified":"1F483-1F3FC","image":"1f483-1f3fc.png","sheet_x":19,"sheet_y":5,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F483-1F3FD":{"unified":"1F483-1F3FD","image":"1f483-1f3fd.png","sheet_x":19,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F483-1F3FE":{"unified":"1F483-1F3FE","image":"1f483-1f3fe.png","sheet_x":19,"sheet_y":7,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F483-1F3FF":{"unified":"1F483-1F3FF","image":"1f483-1f3ff.png","sheet_x":19,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"LIPSTICK","unified":"1F484","variations":[],"docomo":"E710","au":"E509","softbank":"E31C","google":"FE195","image":"1f484.png","sheet_x":19,"sheet_y":9,"short_name":"lipstick","short_names":["lipstick"],"text":null,"texts":null,"category":"People","sort_order":183,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NAIL POLISH","unified":"1F485","variations":[],"docomo":null,"au":"EAA0","softbank":"E31D","google":"FE196","image":"1f485.png","sheet_x":19,"sheet_y":10,"short_name":"nail_care","short_names":["nail_care"],"text":null,"texts":null,"category":"People","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F485-1F3FB":{"unified":"1F485-1F3FB","image":"1f485-1f3fb.png","sheet_x":19,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F485-1F3FC":{"unified":"1F485-1F3FC","image":"1f485-1f3fc.png","sheet_x":19,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F485-1F3FD":{"unified":"1F485-1F3FD","image":"1f485-1f3fd.png","sheet_x":19,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F485-1F3FE":{"unified":"1F485-1F3FE","image":"1f485-1f3fe.png","sheet_x":19,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F485-1F3FF":{"unified":"1F485-1F3FF","image":"1f485-1f3ff.png","sheet_x":19,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"FACE MASSAGE","unified":"1F486","variations":[],"docomo":null,"au":"E50B","softbank":"E31E","google":"FE197","image":"1f486.png","sheet_x":19,"sheet_y":16,"short_name":"massage","short_names":["massage"],"text":null,"texts":null,"category":"People","sort_order":154,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F486-1F3FB":{"unified":"1F486-1F3FB","image":"1f486-1f3fb.png","sheet_x":19,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F486-1F3FC":{"unified":"1F486-1F3FC","image":"1f486-1f3fc.png","sheet_x":19,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F486-1F3FD":{"unified":"1F486-1F3FD","image":"1f486-1f3fd.png","sheet_x":19,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F486-1F3FE":{"unified":"1F486-1F3FE","image":"1f486-1f3fe.png","sheet_x":19,"sheet_y":20,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F486-1F3FF":{"unified":"1F486-1F3FF","image":"1f486-1f3ff.png","sheet_x":19,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"HAIRCUT","unified":"1F487","variations":[],"docomo":"E675","au":"EAA1","softbank":"E31F","google":"FE198","image":"1f487.png","sheet_x":19,"sheet_y":22,"short_name":"haircut","short_names":["haircut"],"text":null,"texts":null,"category":"People","sort_order":153,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F487-1F3FB":{"unified":"1F487-1F3FB","image":"1f487-1f3fb.png","sheet_x":19,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F487-1F3FC":{"unified":"1F487-1F3FC","image":"1f487-1f3fc.png","sheet_x":19,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F487-1F3FD":{"unified":"1F487-1F3FD","image":"1f487-1f3fd.png","sheet_x":19,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F487-1F3FE":{"unified":"1F487-1F3FE","image":"1f487-1f3fe.png","sheet_x":19,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F487-1F3FF":{"unified":"1F487-1F3FF","image":"1f487-1f3ff.png","sheet_x":19,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"BARBER POLE","unified":"1F488","variations":[],"docomo":null,"au":"EAA2","softbank":"E320","google":"FE199","image":"1f488.png","sheet_x":19,"sheet_y":28,"short_name":"barber","short_names":["barber"],"text":null,"texts":null,"category":"Objects","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SYRINGE","unified":"1F489","variations":[],"docomo":null,"au":"E510","softbank":"E13B","google":"FE509","image":"1f489.png","sheet_x":19,"sheet_y":29,"short_name":"syringe","short_names":["syringe"],"text":null,"texts":null,"category":"Objects","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PILL","unified":"1F48A","variations":[],"docomo":null,"au":"EA9A","softbank":"E30F","google":"FE50A","image":"1f48a.png","sheet_x":19,"sheet_y":30,"short_name":"pill","short_names":["pill"],"text":null,"texts":null,"category":"Objects","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISS MARK","unified":"1F48B","variations":[],"docomo":"E6F9","au":"E4EB","softbank":"E003","google":"FE823","image":"1f48b.png","sheet_x":19,"sheet_y":31,"short_name":"kiss","short_names":["kiss"],"text":null,"texts":[":*",":-*"],"category":"People","sort_order":184,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOVE LETTER","unified":"1F48C","variations":[],"docomo":"E717","au":"EB78","softbank":"E103-E328","google":"FE824","image":"1f48c.png","sheet_x":19,"sheet_y":32,"short_name":"love_letter","short_names":["love_letter"],"text":null,"texts":null,"category":"Objects","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RING","unified":"1F48D","variations":[],"docomo":"E71B","au":"E514","softbank":"E034","google":"FE825","image":"1f48d.png","sheet_x":19,"sheet_y":33,"short_name":"ring","short_names":["ring"],"text":null,"texts":null,"category":"People","sort_order":203,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GEM STONE","unified":"1F48E","variations":[],"docomo":"E71B","au":"E514","softbank":"E035","google":"FE826","image":"1f48e.png","sheet_x":19,"sheet_y":34,"short_name":"gem","short_names":["gem"],"text":null,"texts":null,"category":"Objects","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISS","unified":"1F48F","variations":[],"docomo":"E6F9","au":"E5CA","softbank":"E111","google":"FE827","image":"1f48f.png","sheet_x":19,"sheet_y":35,"short_name":"couplekiss","short_names":["couplekiss"],"text":null,"texts":null,"category":"People","sort_order":158,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOUQUET","unified":"1F490","variations":[],"docomo":null,"au":"EA95","softbank":"E306","google":"FE828","image":"1f490.png","sheet_x":19,"sheet_y":36,"short_name":"bouquet","short_names":["bouquet"],"text":null,"texts":null,"category":"Nature","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COUPLE WITH HEART","unified":"1F491","variations":[],"docomo":"E6ED","au":"EADA","softbank":"E425","google":"FE829","image":"1f491.png","sheet_x":19,"sheet_y":37,"short_name":"couple_with_heart","short_names":["couple_with_heart"],"text":null,"texts":null,"category":"People","sort_order":155,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WEDDING","unified":"1F492","variations":[],"docomo":null,"au":"E5BB","softbank":"E43D","google":"FE82A","image":"1f492.png","sheet_x":19,"sheet_y":38,"short_name":"wedding","short_names":["wedding"],"text":null,"texts":null,"category":"Places","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BEATING HEART","unified":"1F493","variations":[],"docomo":"E6ED","au":"EB75","softbank":"E327","google":"FEB0D","image":"1f493.png","sheet_x":19,"sheet_y":39,"short_name":"heartbeat","short_names":["heartbeat"],"text":null,"texts":null,"category":"Symbols","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BROKEN HEART","unified":"1F494","variations":[],"docomo":"E6EE","au":"E477","softbank":"E023","google":"FEB0E","image":"1f494.png","sheet_x":19,"sheet_y":40,"short_name":"broken_heart","short_names":["broken_heart"],"text":"<\/3","texts":["<\/3"],"category":"Symbols","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TWO HEARTS","unified":"1F495","variations":[],"docomo":"E6EF","au":"E478","softbank":"E327","google":"FEB0F","image":"1f495.png","sheet_x":20,"sheet_y":0,"short_name":"two_hearts","short_names":["two_hearts"],"text":null,"texts":null,"category":"Symbols","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPARKLING HEART","unified":"1F496","variations":[],"docomo":"E6EC","au":"EAA6","softbank":"E327","google":"FEB10","image":"1f496.png","sheet_x":20,"sheet_y":1,"short_name":"sparkling_heart","short_names":["sparkling_heart"],"text":null,"texts":null,"category":"Symbols","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GROWING HEART","unified":"1F497","variations":[],"docomo":"E6ED","au":"EB75","softbank":"E328","google":"FEB11","image":"1f497.png","sheet_x":20,"sheet_y":2,"short_name":"heartpulse","short_names":["heartpulse"],"text":null,"texts":null,"category":"Symbols","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEART WITH ARROW","unified":"1F498","variations":[],"docomo":"E6EC","au":"E4EA","softbank":"E329","google":"FEB12","image":"1f498.png","sheet_x":20,"sheet_y":3,"short_name":"cupid","short_names":["cupid"],"text":null,"texts":null,"category":"Symbols","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLUE HEART","unified":"1F499","variations":[],"docomo":"E6EC","au":"EAA7","softbank":"E32A","google":"FEB13","image":"1f499.png","sheet_x":20,"sheet_y":4,"short_name":"blue_heart","short_names":["blue_heart"],"text":"<3","texts":null,"category":"Symbols","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GREEN HEART","unified":"1F49A","variations":[],"docomo":"E6EC","au":"EAA8","softbank":"E32B","google":"FEB14","image":"1f49a.png","sheet_x":20,"sheet_y":5,"short_name":"green_heart","short_names":["green_heart"],"text":"<3","texts":null,"category":"Symbols","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"YELLOW HEART","unified":"1F49B","variations":[],"docomo":"E6EC","au":"EAA9","softbank":"E32C","google":"FEB15","image":"1f49b.png","sheet_x":20,"sheet_y":6,"short_name":"yellow_heart","short_names":["yellow_heart"],"text":"<3","texts":null,"category":"Symbols","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PURPLE HEART","unified":"1F49C","variations":[],"docomo":"E6EC","au":"EAAA","softbank":"E32D","google":"FEB16","image":"1f49c.png","sheet_x":20,"sheet_y":7,"short_name":"purple_heart","short_names":["purple_heart"],"text":"<3","texts":null,"category":"Symbols","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEART WITH RIBBON","unified":"1F49D","variations":[],"docomo":"E6EC","au":"EB54","softbank":"E437","google":"FEB17","image":"1f49d.png","sheet_x":20,"sheet_y":8,"short_name":"gift_heart","short_names":["gift_heart"],"text":null,"texts":null,"category":"Symbols","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REVOLVING HEARTS","unified":"1F49E","variations":[],"docomo":"E6ED","au":"E5AF","softbank":"E327","google":"FEB18","image":"1f49e.png","sheet_x":20,"sheet_y":9,"short_name":"revolving_hearts","short_names":["revolving_hearts"],"text":null,"texts":null,"category":"Symbols","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEART DECORATION","unified":"1F49F","variations":[],"docomo":"E6F8","au":"E595","softbank":"E204","google":"FEB19","image":"1f49f.png","sheet_x":20,"sheet_y":10,"short_name":"heart_decoration","short_names":["heart_decoration"],"text":null,"texts":null,"category":"Symbols","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DIAMOND SHAPE WITH A DOT INSIDE","unified":"1F4A0","variations":[],"docomo":"E6F8","au":null,"softbank":null,"google":"FEB55","image":"1f4a0.png","sheet_x":20,"sheet_y":11,"short_name":"diamond_shape_with_a_dot_inside","short_names":["diamond_shape_with_a_dot_inside"],"text":null,"texts":null,"category":"Symbols","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ELECTRIC LIGHT BULB","unified":"1F4A1","variations":[],"docomo":"E6FB","au":"E476","softbank":"E10F","google":"FEB56","image":"1f4a1.png","sheet_x":20,"sheet_y":12,"short_name":"bulb","short_names":["bulb"],"text":null,"texts":null,"category":"Objects","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANGER SYMBOL","unified":"1F4A2","variations":[],"docomo":"E6FC","au":"E4E5","softbank":"E334","google":"FEB57","image":"1f4a2.png","sheet_x":20,"sheet_y":13,"short_name":"anger","short_names":["anger"],"text":null,"texts":null,"category":"Symbols","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOMB","unified":"1F4A3","variations":[],"docomo":"E6FE","au":"E47A","softbank":"E311","google":"FEB58","image":"1f4a3.png","sheet_x":20,"sheet_y":14,"short_name":"bomb","short_names":["bomb"],"text":null,"texts":null,"category":"Objects","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLEEPING SYMBOL","unified":"1F4A4","variations":[],"docomo":"E701","au":"E475","softbank":"E13C","google":"FEB59","image":"1f4a4.png","sheet_x":20,"sheet_y":15,"short_name":"zzz","short_names":["zzz"],"text":null,"texts":null,"category":"People","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COLLISION SYMBOL","unified":"1F4A5","variations":[],"docomo":"E705","au":"E5B0","softbank":null,"google":"FEB5A","image":"1f4a5.png","sheet_x":20,"sheet_y":16,"short_name":"boom","short_names":["boom","collision"],"text":null,"texts":null,"category":"Nature","sort_order":134,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPLASHING SWEAT SYMBOL","unified":"1F4A6","variations":[],"docomo":"E706","au":"E5B1","softbank":"E331","google":"FEB5B","image":"1f4a6.png","sheet_x":20,"sheet_y":17,"short_name":"sweat_drops","short_names":["sweat_drops"],"text":null,"texts":null,"category":"Nature","sort_order":146,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DROPLET","unified":"1F4A7","variations":[],"docomo":"E707","au":"E4E6","softbank":"E331","google":"FEB5C","image":"1f4a7.png","sheet_x":20,"sheet_y":18,"short_name":"droplet","short_names":["droplet"],"text":null,"texts":null,"category":"Nature","sort_order":145,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DASH SYMBOL","unified":"1F4A8","variations":[],"docomo":"E708","au":"E4F4","softbank":"E330","google":"FEB5D","image":"1f4a8.png","sheet_x":20,"sheet_y":19,"short_name":"dash","short_names":["dash"],"text":null,"texts":null,"category":"Nature","sort_order":140,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PILE OF POO","unified":"1F4A9","variations":[],"docomo":null,"au":"E4F5","softbank":"E05A","google":"FE4F4","image":"1f4a9.png","sheet_x":20,"sheet_y":20,"short_name":"hankey","short_names":["hankey","poop","shit"],"text":null,"texts":null,"category":"People","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLEXED BICEPS","unified":"1F4AA","variations":[],"docomo":null,"au":"E4E9","softbank":"E14C","google":"FEB5E","image":"1f4aa.png","sheet_x":20,"sheet_y":21,"short_name":"muscle","short_names":["muscle"],"text":null,"texts":null,"category":"People","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F4AA-1F3FB":{"unified":"1F4AA-1F3FB","image":"1f4aa-1f3fb.png","sheet_x":20,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F4AA-1F3FC":{"unified":"1F4AA-1F3FC","image":"1f4aa-1f3fc.png","sheet_x":20,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F4AA-1F3FD":{"unified":"1F4AA-1F3FD","image":"1f4aa-1f3fd.png","sheet_x":20,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F4AA-1F3FE":{"unified":"1F4AA-1F3FE","image":"1f4aa-1f3fe.png","sheet_x":20,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F4AA-1F3FF":{"unified":"1F4AA-1F3FF","image":"1f4aa-1f3ff.png","sheet_x":20,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"DIZZY SYMBOL","unified":"1F4AB","variations":[],"docomo":null,"au":"EB5C","softbank":"E407","google":"FEB5F","image":"1f4ab.png","sheet_x":20,"sheet_y":27,"short_name":"dizzy","short_names":["dizzy"],"text":null,"texts":null,"category":"Nature","sort_order":120,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEECH BALLOON","unified":"1F4AC","variations":[],"docomo":null,"au":"E4FD","softbank":null,"google":"FE532","image":"1f4ac.png","sheet_x":20,"sheet_y":28,"short_name":"speech_balloon","short_names":["speech_balloon"],"text":null,"texts":null,"category":"Symbols","sort_order":245,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"THOUGHT BALLOON","unified":"1F4AD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4ad.png","sheet_x":20,"sheet_y":29,"short_name":"thought_balloon","short_names":["thought_balloon"],"text":null,"texts":null,"category":"Symbols","sort_order":243,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE FLOWER","unified":"1F4AE","variations":[],"docomo":null,"au":"E4F0","softbank":null,"google":"FEB7A","image":"1f4ae.png","sheet_x":20,"sheet_y":30,"short_name":"white_flower","short_names":["white_flower"],"text":null,"texts":null,"category":"Symbols","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HUNDRED POINTS SYMBOL","unified":"1F4AF","variations":[],"docomo":null,"au":"E4F2","softbank":null,"google":"FEB7B","image":"1f4af.png","sheet_x":20,"sheet_y":31,"short_name":"100","short_names":["100"],"text":null,"texts":null,"category":"Symbols","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONEY BAG","unified":"1F4B0","variations":[],"docomo":"E715","au":"E4C7","softbank":"E12F","google":"FE4DD","image":"1f4b0.png","sheet_x":20,"sheet_y":32,"short_name":"moneybag","short_names":["moneybag"],"text":null,"texts":null,"category":"Objects","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CURRENCY EXCHANGE","unified":"1F4B1","variations":[],"docomo":null,"au":null,"softbank":"E149","google":"FE4DE","image":"1f4b1.png","sheet_x":20,"sheet_y":33,"short_name":"currency_exchange","short_names":["currency_exchange"],"text":null,"texts":null,"category":"Symbols","sort_order":196,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAVY DOLLAR SIGN","unified":"1F4B2","variations":[],"docomo":"E715","au":"E579","softbank":"E12F","google":"FE4E0","image":"1f4b2.png","sheet_x":20,"sheet_y":34,"short_name":"heavy_dollar_sign","short_names":["heavy_dollar_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":195,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CREDIT CARD","unified":"1F4B3","variations":[],"docomo":null,"au":"E57C","softbank":null,"google":"FE4E1","image":"1f4b3.png","sheet_x":20,"sheet_y":35,"short_name":"credit_card","short_names":["credit_card"],"text":null,"texts":null,"category":"Objects","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANKNOTE WITH YEN SIGN","unified":"1F4B4","variations":[],"docomo":"E6D6","au":"E57D","softbank":null,"google":"FE4E2","image":"1f4b4.png","sheet_x":20,"sheet_y":36,"short_name":"yen","short_names":["yen"],"text":null,"texts":null,"category":"Objects","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANKNOTE WITH DOLLAR SIGN","unified":"1F4B5","variations":[],"docomo":"E715","au":"E585","softbank":"E12F","google":"FE4E3","image":"1f4b5.png","sheet_x":20,"sheet_y":37,"short_name":"dollar","short_names":["dollar"],"text":null,"texts":null,"category":"Objects","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANKNOTE WITH EURO SIGN","unified":"1F4B6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4b6.png","sheet_x":20,"sheet_y":38,"short_name":"euro","short_names":["euro"],"text":null,"texts":null,"category":"Objects","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BANKNOTE WITH POUND SIGN","unified":"1F4B7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4b7.png","sheet_x":20,"sheet_y":39,"short_name":"pound","short_names":["pound"],"text":null,"texts":null,"category":"Objects","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONEY WITH WINGS","unified":"1F4B8","variations":[],"docomo":null,"au":"EB5B","softbank":null,"google":"FE4E4","image":"1f4b8.png","sheet_x":20,"sheet_y":40,"short_name":"money_with_wings","short_names":["money_with_wings"],"text":null,"texts":null,"category":"Objects","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHART WITH UPWARDS TREND AND YEN SIGN","unified":"1F4B9","variations":[],"docomo":null,"au":"E5DC","softbank":"E14A","google":"FE4DF","image":"1f4b9.png","sheet_x":21,"sheet_y":0,"short_name":"chart","short_names":["chart"],"text":null,"texts":null,"category":"Symbols","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SEAT","unified":"1F4BA","variations":[],"docomo":"E6B2","au":null,"softbank":"E11F","google":"FE537","image":"1f4ba.png","sheet_x":21,"sheet_y":1,"short_name":"seat","short_names":["seat"],"text":null,"texts":null,"category":"Places","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PERSONAL COMPUTER","unified":"1F4BB","variations":[],"docomo":"E716","au":"E5B8","softbank":"E00C","google":"FE538","image":"1f4bb.png","sheet_x":21,"sheet_y":2,"short_name":"computer","short_names":["computer"],"text":null,"texts":null,"category":"Objects","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BRIEFCASE","unified":"1F4BC","variations":[],"docomo":"E682","au":"E5CE","softbank":"E11E","google":"FE53B","image":"1f4bc.png","sheet_x":21,"sheet_y":3,"short_name":"briefcase","short_names":["briefcase"],"text":null,"texts":null,"category":"People","sort_order":200,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MINIDISC","unified":"1F4BD","variations":[],"docomo":null,"au":"E582","softbank":"E316","google":"FE53C","image":"1f4bd.png","sheet_x":21,"sheet_y":4,"short_name":"minidisc","short_names":["minidisc"],"text":null,"texts":null,"category":"Objects","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLOPPY DISK","unified":"1F4BE","variations":[],"docomo":null,"au":"E562","softbank":"E316","google":"FE53D","image":"1f4be.png","sheet_x":21,"sheet_y":5,"short_name":"floppy_disk","short_names":["floppy_disk"],"text":null,"texts":null,"category":"Objects","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPTICAL DISC","unified":"1F4BF","variations":[],"docomo":"E68C","au":"E50C","softbank":"E126","google":"FE81D","image":"1f4bf.png","sheet_x":21,"sheet_y":6,"short_name":"cd","short_names":["cd"],"text":null,"texts":null,"category":"Objects","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DVD","unified":"1F4C0","variations":[],"docomo":"E68C","au":"E50C","softbank":"E127","google":"FE81E","image":"1f4c0.png","sheet_x":21,"sheet_y":7,"short_name":"dvd","short_names":["dvd"],"text":null,"texts":null,"category":"Objects","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FILE FOLDER","unified":"1F4C1","variations":[],"docomo":null,"au":"E58F","softbank":null,"google":"FE543","image":"1f4c1.png","sheet_x":21,"sheet_y":8,"short_name":"file_folder","short_names":["file_folder"],"text":null,"texts":null,"category":"Objects","sort_order":141,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPEN FILE FOLDER","unified":"1F4C2","variations":[],"docomo":null,"au":"E590","softbank":null,"google":"FE544","image":"1f4c2.png","sheet_x":21,"sheet_y":9,"short_name":"open_file_folder","short_names":["open_file_folder"],"text":null,"texts":null,"category":"Objects","sort_order":142,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PAGE WITH CURL","unified":"1F4C3","variations":[],"docomo":"E689","au":"E561","softbank":"E301","google":"FE540","image":"1f4c3.png","sheet_x":21,"sheet_y":10,"short_name":"page_with_curl","short_names":["page_with_curl"],"text":null,"texts":null,"category":"Objects","sort_order":126,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PAGE FACING UP","unified":"1F4C4","variations":[],"docomo":"E689","au":"E569","softbank":"E301","google":"FE541","image":"1f4c4.png","sheet_x":21,"sheet_y":11,"short_name":"page_facing_up","short_names":["page_facing_up"],"text":null,"texts":null,"category":"Objects","sort_order":131,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CALENDAR","unified":"1F4C5","variations":[],"docomo":null,"au":"E563","softbank":null,"google":"FE542","image":"1f4c5.png","sheet_x":21,"sheet_y":12,"short_name":"date","short_names":["date"],"text":null,"texts":null,"category":"Objects","sort_order":132,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TEAR-OFF CALENDAR","unified":"1F4C6","variations":[],"docomo":null,"au":"E56A","softbank":null,"google":"FE549","image":"1f4c6.png","sheet_x":21,"sheet_y":13,"short_name":"calendar","short_names":["calendar"],"text":null,"texts":null,"category":"Objects","sort_order":133,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CARD INDEX","unified":"1F4C7","variations":[],"docomo":"E683","au":"E56C","softbank":"E148","google":"FE54D","image":"1f4c7.png","sheet_x":21,"sheet_y":14,"short_name":"card_index","short_names":["card_index"],"text":null,"texts":null,"category":"Objects","sort_order":135,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHART WITH UPWARDS TREND","unified":"1F4C8","variations":[],"docomo":null,"au":"E575","softbank":"E14A","google":"FE54B","image":"1f4c8.png","sheet_x":21,"sheet_y":15,"short_name":"chart_with_upwards_trend","short_names":["chart_with_upwards_trend"],"text":null,"texts":null,"category":"Objects","sort_order":129,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHART WITH DOWNWARDS TREND","unified":"1F4C9","variations":[],"docomo":null,"au":"E576","softbank":null,"google":"FE54C","image":"1f4c9.png","sheet_x":21,"sheet_y":16,"short_name":"chart_with_downwards_trend","short_names":["chart_with_downwards_trend"],"text":null,"texts":null,"category":"Objects","sort_order":130,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BAR CHART","unified":"1F4CA","variations":[],"docomo":null,"au":"E574","softbank":"E14A","google":"FE54A","image":"1f4ca.png","sheet_x":21,"sheet_y":17,"short_name":"bar_chart","short_names":["bar_chart"],"text":null,"texts":null,"category":"Objects","sort_order":128,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLIPBOARD","unified":"1F4CB","variations":[],"docomo":"E689","au":"E564","softbank":"E301","google":"FE548","image":"1f4cb.png","sheet_x":21,"sheet_y":18,"short_name":"clipboard","short_names":["clipboard"],"text":null,"texts":null,"category":"Objects","sort_order":139,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PUSHPIN","unified":"1F4CC","variations":[],"docomo":null,"au":"E56D","softbank":null,"google":"FE54E","image":"1f4cc.png","sheet_x":21,"sheet_y":19,"short_name":"pushpin","short_names":["pushpin"],"text":null,"texts":null,"category":"Objects","sort_order":161,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROUND PUSHPIN","unified":"1F4CD","variations":[],"docomo":null,"au":"E560","softbank":null,"google":"FE53F","image":"1f4cd.png","sheet_x":21,"sheet_y":20,"short_name":"round_pushpin","short_names":["round_pushpin"],"text":null,"texts":null,"category":"Objects","sort_order":162,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PAPERCLIP","unified":"1F4CE","variations":[],"docomo":"E730","au":"E4A0","softbank":null,"google":"FE53A","image":"1f4ce.png","sheet_x":21,"sheet_y":21,"short_name":"paperclip","short_names":["paperclip"],"text":null,"texts":null,"category":"Objects","sort_order":156,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STRAIGHT RULER","unified":"1F4CF","variations":[],"docomo":null,"au":"E570","softbank":null,"google":"FE550","image":"1f4cf.png","sheet_x":21,"sheet_y":22,"short_name":"straight_ruler","short_names":["straight_ruler"],"text":null,"texts":null,"category":"Objects","sort_order":160,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRIANGULAR RULER","unified":"1F4D0","variations":[],"docomo":null,"au":"E4A2","softbank":null,"google":"FE551","image":"1f4d0.png","sheet_x":21,"sheet_y":23,"short_name":"triangular_ruler","short_names":["triangular_ruler"],"text":null,"texts":null,"category":"Objects","sort_order":159,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOOKMARK TABS","unified":"1F4D1","variations":[],"docomo":"E689","au":"EB0B","softbank":"E301","google":"FE552","image":"1f4d1.png","sheet_x":21,"sheet_y":24,"short_name":"bookmark_tabs","short_names":["bookmark_tabs"],"text":null,"texts":null,"category":"Objects","sort_order":127,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEDGER","unified":"1F4D2","variations":[],"docomo":"E683","au":"E56E","softbank":"E148","google":"FE54F","image":"1f4d2.png","sheet_x":21,"sheet_y":25,"short_name":"ledger","short_names":["ledger"],"text":null,"texts":null,"category":"Objects","sort_order":152,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NOTEBOOK","unified":"1F4D3","variations":[],"docomo":"E683","au":"E56B","softbank":"E148","google":"FE545","image":"1f4d3.png","sheet_x":21,"sheet_y":26,"short_name":"notebook","short_names":["notebook"],"text":null,"texts":null,"category":"Objects","sort_order":146,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NOTEBOOK WITH DECORATIVE COVER","unified":"1F4D4","variations":[],"docomo":"E683","au":"E49D","softbank":"E148","google":"FE547","image":"1f4d4.png","sheet_x":21,"sheet_y":27,"short_name":"notebook_with_decorative_cover","short_names":["notebook_with_decorative_cover"],"text":null,"texts":null,"category":"Objects","sort_order":151,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOSED BOOK","unified":"1F4D5","variations":[],"docomo":"E683","au":"E568","softbank":"E148","google":"FE502","image":"1f4d5.png","sheet_x":21,"sheet_y":28,"short_name":"closed_book","short_names":["closed_book"],"text":null,"texts":null,"category":"Objects","sort_order":147,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPEN BOOK","unified":"1F4D6","variations":[],"docomo":"E683","au":"E49F","softbank":"E148","google":"FE546","image":"1f4d6.png","sheet_x":21,"sheet_y":29,"short_name":"book","short_names":["book","open_book"],"text":null,"texts":null,"category":"Objects","sort_order":154,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GREEN BOOK","unified":"1F4D7","variations":[],"docomo":"E683","au":"E565","softbank":"E148","google":"FE4FF","image":"1f4d7.png","sheet_x":21,"sheet_y":30,"short_name":"green_book","short_names":["green_book"],"text":null,"texts":null,"category":"Objects","sort_order":148,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLUE BOOK","unified":"1F4D8","variations":[],"docomo":"E683","au":"E566","softbank":"E148","google":"FE500","image":"1f4d8.png","sheet_x":21,"sheet_y":31,"short_name":"blue_book","short_names":["blue_book"],"text":null,"texts":null,"category":"Objects","sort_order":149,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ORANGE BOOK","unified":"1F4D9","variations":[],"docomo":"E683","au":"E567","softbank":"E148","google":"FE501","image":"1f4d9.png","sheet_x":21,"sheet_y":32,"short_name":"orange_book","short_names":["orange_book"],"text":null,"texts":null,"category":"Objects","sort_order":150,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOOKS","unified":"1F4DA","variations":[],"docomo":"E683","au":"E56F","softbank":"E148","google":"FE503","image":"1f4da.png","sheet_x":21,"sheet_y":33,"short_name":"books","short_names":["books"],"text":null,"texts":null,"category":"Objects","sort_order":153,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NAME BADGE","unified":"1F4DB","variations":[],"docomo":null,"au":"E51D","softbank":null,"google":"FE504","image":"1f4db.png","sheet_x":21,"sheet_y":34,"short_name":"name_badge","short_names":["name_badge"],"text":null,"texts":null,"category":"Symbols","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCROLL","unified":"1F4DC","variations":[],"docomo":"E70A","au":"E55F","softbank":null,"google":"FE4FD","image":"1f4dc.png","sheet_x":21,"sheet_y":35,"short_name":"scroll","short_names":["scroll"],"text":null,"texts":null,"category":"Objects","sort_order":125,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MEMO","unified":"1F4DD","variations":[],"docomo":"E689","au":"EA92","softbank":"E301","google":"FE527","image":"1f4dd.png","sheet_x":21,"sheet_y":36,"short_name":"memo","short_names":["memo","pencil"],"text":null,"texts":null,"category":"Objects","sort_order":173,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TELEPHONE RECEIVER","unified":"1F4DE","variations":[],"docomo":"E687","au":"E51E","softbank":"E009","google":"FE524","image":"1f4de.png","sheet_x":21,"sheet_y":37,"short_name":"telephone_receiver","short_names":["telephone_receiver"],"text":null,"texts":null,"category":"Objects","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PAGER","unified":"1F4DF","variations":[],"docomo":"E65A","au":"E59B","softbank":null,"google":"FE522","image":"1f4df.png","sheet_x":21,"sheet_y":38,"short_name":"pager","short_names":["pager"],"text":null,"texts":null,"category":"Objects","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FAX MACHINE","unified":"1F4E0","variations":[],"docomo":"E6D0","au":"E520","softbank":"E00B","google":"FE528","image":"1f4e0.png","sheet_x":21,"sheet_y":39,"short_name":"fax","short_names":["fax"],"text":null,"texts":null,"category":"Objects","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SATELLITE ANTENNA","unified":"1F4E1","variations":[],"docomo":null,"au":"E4A8","softbank":"E14B","google":"FE531","image":"1f4e1.png","sheet_x":21,"sheet_y":40,"short_name":"satellite","short_names":["satellite"],"text":null,"texts":null,"category":"Objects","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PUBLIC ADDRESS LOUDSPEAKER","unified":"1F4E2","variations":[],"docomo":null,"au":"E511","softbank":"E142","google":"FE52F","image":"1f4e2.png","sheet_x":22,"sheet_y":0,"short_name":"loudspeaker","short_names":["loudspeaker"],"text":null,"texts":null,"category":"Symbols","sort_order":232,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHEERING MEGAPHONE","unified":"1F4E3","variations":[],"docomo":null,"au":"E511","softbank":"E317","google":"FE530","image":"1f4e3.png","sheet_x":22,"sheet_y":1,"short_name":"mega","short_names":["mega"],"text":null,"texts":null,"category":"Symbols","sort_order":231,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OUTBOX TRAY","unified":"1F4E4","variations":[],"docomo":null,"au":"E592","softbank":null,"google":"FE533","image":"1f4e4.png","sheet_x":22,"sheet_y":2,"short_name":"outbox_tray","short_names":["outbox_tray"],"text":null,"texts":null,"category":"Objects","sort_order":124,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INBOX TRAY","unified":"1F4E5","variations":[],"docomo":null,"au":"E593","softbank":null,"google":"FE534","image":"1f4e5.png","sheet_x":22,"sheet_y":3,"short_name":"inbox_tray","short_names":["inbox_tray"],"text":null,"texts":null,"category":"Objects","sort_order":123,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PACKAGE","unified":"1F4E6","variations":[],"docomo":"E685","au":"E51F","softbank":"E112","google":"FE535","image":"1f4e6.png","sheet_x":22,"sheet_y":4,"short_name":"package","short_names":["package"],"text":null,"texts":null,"category":"Objects","sort_order":121,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"E-MAIL SYMBOL","unified":"1F4E7","variations":[],"docomo":"E6D3","au":"EB71","softbank":"E103","google":"FEB92","image":"1f4e7.png","sheet_x":22,"sheet_y":5,"short_name":"e-mail","short_names":["e-mail"],"text":null,"texts":null,"category":"Objects","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INCOMING ENVELOPE","unified":"1F4E8","variations":[],"docomo":"E6CF","au":"E591","softbank":"E103","google":"FE52A","image":"1f4e8.png","sheet_x":22,"sheet_y":6,"short_name":"incoming_envelope","short_names":["incoming_envelope"],"text":null,"texts":null,"category":"Objects","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ENVELOPE WITH DOWNWARDS ARROW ABOVE","unified":"1F4E9","variations":[],"docomo":"E6CF","au":"EB62","softbank":"E103","google":"FE52B","image":"1f4e9.png","sheet_x":22,"sheet_y":7,"short_name":"envelope_with_arrow","short_names":["envelope_with_arrow"],"text":null,"texts":null,"category":"Objects","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOSED MAILBOX WITH LOWERED FLAG","unified":"1F4EA","variations":[],"docomo":"E665","au":"E51B","softbank":"E101","google":"FE52C","image":"1f4ea.png","sheet_x":22,"sheet_y":8,"short_name":"mailbox_closed","short_names":["mailbox_closed"],"text":null,"texts":null,"category":"Objects","sort_order":117,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOSED MAILBOX WITH RAISED FLAG","unified":"1F4EB","variations":[],"docomo":"E665","au":"EB0A","softbank":"E101","google":"FE52D","image":"1f4eb.png","sheet_x":22,"sheet_y":9,"short_name":"mailbox","short_names":["mailbox"],"text":null,"texts":null,"category":"Objects","sort_order":118,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPEN MAILBOX WITH RAISED FLAG","unified":"1F4EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4ec.png","sheet_x":22,"sheet_y":10,"short_name":"mailbox_with_mail","short_names":["mailbox_with_mail"],"text":null,"texts":null,"category":"Objects","sort_order":119,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPEN MAILBOX WITH LOWERED FLAG","unified":"1F4ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4ed.png","sheet_x":22,"sheet_y":11,"short_name":"mailbox_with_no_mail","short_names":["mailbox_with_no_mail"],"text":null,"texts":null,"category":"Objects","sort_order":120,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POSTBOX","unified":"1F4EE","variations":[],"docomo":"E665","au":"E51B","softbank":"E102","google":"FE52E","image":"1f4ee.png","sheet_x":22,"sheet_y":12,"short_name":"postbox","short_names":["postbox"],"text":null,"texts":null,"category":"Objects","sort_order":116,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POSTAL HORN","unified":"1F4EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4ef.png","sheet_x":22,"sheet_y":13,"short_name":"postal_horn","short_names":["postal_horn"],"text":null,"texts":null,"category":"Objects","sort_order":122,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEWSPAPER","unified":"1F4F0","variations":[],"docomo":null,"au":"E58B","softbank":null,"google":"FE822","image":"1f4f0.png","sheet_x":22,"sheet_y":14,"short_name":"newspaper","short_names":["newspaper"],"text":null,"texts":null,"category":"Objects","sort_order":145,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOBILE PHONE","unified":"1F4F1","variations":[],"docomo":"E688","au":"E588","softbank":"E00A","google":"FE525","image":"1f4f1.png","sheet_x":22,"sheet_y":15,"short_name":"iphone","short_names":["iphone"],"text":null,"texts":null,"category":"Objects","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT","unified":"1F4F2","variations":[],"docomo":"E6CE","au":"EB08","softbank":"E104","google":"FE526","image":"1f4f2.png","sheet_x":22,"sheet_y":16,"short_name":"calling","short_names":["calling"],"text":null,"texts":null,"category":"Objects","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIBRATION MODE","unified":"1F4F3","variations":[],"docomo":null,"au":"EA90","softbank":"E250","google":"FE839","image":"1f4f3.png","sheet_x":22,"sheet_y":17,"short_name":"vibration_mode","short_names":["vibration_mode"],"text":null,"texts":null,"category":"Symbols","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOBILE PHONE OFF","unified":"1F4F4","variations":[],"docomo":null,"au":"EA91","softbank":"E251","google":"FE83A","image":"1f4f4.png","sheet_x":22,"sheet_y":18,"short_name":"mobile_phone_off","short_names":["mobile_phone_off"],"text":null,"texts":null,"category":"Symbols","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO MOBILE PHONES","unified":"1F4F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4f5.png","sheet_x":22,"sheet_y":19,"short_name":"no_mobile_phones","short_names":["no_mobile_phones"],"text":null,"texts":null,"category":"Symbols","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANTENNA WITH BARS","unified":"1F4F6","variations":[],"docomo":null,"au":"EA84","softbank":"E20B","google":"FE838","image":"1f4f6.png","sheet_x":22,"sheet_y":20,"short_name":"signal_strength","short_names":["signal_strength"],"text":null,"texts":null,"category":"Symbols","sort_order":126,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAMERA","unified":"1F4F7","variations":[],"docomo":"E681","au":"E515","softbank":"E008","google":"FE4EF","image":"1f4f7.png","sheet_x":22,"sheet_y":21,"short_name":"camera","short_names":["camera"],"text":null,"texts":null,"category":"Objects","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAMERA WITH FLASH","unified":"1F4F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4f8.png","sheet_x":22,"sheet_y":22,"short_name":"camera_with_flash","short_names":["camera_with_flash"],"text":null,"texts":null,"category":"Objects","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIDEO CAMERA","unified":"1F4F9","variations":[],"docomo":"E677","au":"E57E","softbank":"E03D","google":"FE4F9","image":"1f4f9.png","sheet_x":22,"sheet_y":23,"short_name":"video_camera","short_names":["video_camera"],"text":null,"texts":null,"category":"Objects","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TELEVISION","unified":"1F4FA","variations":[],"docomo":"E68A","au":"E502","softbank":"E12A","google":"FE81C","image":"1f4fa.png","sheet_x":22,"sheet_y":24,"short_name":"tv","short_names":["tv"],"text":null,"texts":null,"category":"Objects","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RADIO","unified":"1F4FB","variations":[],"docomo":null,"au":"E5B9","softbank":"E128","google":"FE81F","image":"1f4fb.png","sheet_x":22,"sheet_y":25,"short_name":"radio","short_names":["radio"],"text":null,"texts":null,"category":"Objects","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VIDEOCASSETTE","unified":"1F4FC","variations":[],"docomo":null,"au":"E580","softbank":"E129","google":"FE820","image":"1f4fc.png","sheet_x":22,"sheet_y":26,"short_name":"vhs","short_names":["vhs"],"text":null,"texts":null,"category":"Objects","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FILM PROJECTOR","unified":"1F4FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4fd.png","sheet_x":22,"sheet_y":27,"short_name":"film_projector","short_names":["film_projector"],"text":null,"texts":null,"category":"Objects","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PRAYER BEADS","unified":"1F4FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f4ff.png","sheet_x":22,"sheet_y":28,"short_name":"prayer_beads","short_names":["prayer_beads"],"text":null,"texts":null,"category":"Objects","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TWISTED RIGHTWARDS ARROWS","unified":"1F500","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f500.png","sheet_x":22,"sheet_y":29,"short_name":"twisted_rightwards_arrows","short_names":["twisted_rightwards_arrows"],"text":null,"texts":null,"category":"Symbols","sort_order":155,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS","unified":"1F501","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f501.png","sheet_x":22,"sheet_y":30,"short_name":"repeat","short_names":["repeat"],"text":null,"texts":null,"category":"Symbols","sort_order":156,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY","unified":"1F502","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f502.png","sheet_x":22,"sheet_y":31,"short_name":"repeat_one","short_names":["repeat_one"],"text":null,"texts":null,"category":"Symbols","sort_order":157,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS","unified":"1F503","variations":[],"docomo":"E735","au":"EB0D","softbank":null,"google":"FEB91","image":"1f503.png","sheet_x":22,"sheet_y":32,"short_name":"arrows_clockwise","short_names":["arrows_clockwise"],"text":null,"texts":null,"category":"Symbols","sort_order":190,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS","unified":"1F504","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f504.png","sheet_x":22,"sheet_y":33,"short_name":"arrows_counterclockwise","short_names":["arrows_counterclockwise"],"text":null,"texts":null,"category":"Symbols","sort_order":173,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOW BRIGHTNESS SYMBOL","unified":"1F505","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f505.png","sheet_x":22,"sheet_y":34,"short_name":"low_brightness","short_names":["low_brightness"],"text":null,"texts":null,"category":"Symbols","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIGH BRIGHTNESS SYMBOL","unified":"1F506","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f506.png","sheet_x":22,"sheet_y":35,"short_name":"high_brightness","short_names":["high_brightness"],"text":null,"texts":null,"category":"Symbols","sort_order":90,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAKER WITH CANCELLATION STROKE","unified":"1F507","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f507.png","sheet_x":22,"sheet_y":36,"short_name":"mute","short_names":["mute"],"text":null,"texts":null,"category":"Symbols","sort_order":230,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAKER","unified":"1F508","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f508.png","sheet_x":22,"sheet_y":37,"short_name":"speaker","short_names":["speaker"],"text":null,"texts":null,"category":"Symbols","sort_order":227,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAKER WITH ONE SOUND WAVE","unified":"1F509","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f509.png","sheet_x":22,"sheet_y":38,"short_name":"sound","short_names":["sound"],"text":null,"texts":null,"category":"Symbols","sort_order":228,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAKER WITH THREE SOUND WAVES","unified":"1F50A","variations":[],"docomo":null,"au":"E511","softbank":"E141","google":"FE821","image":"1f50a.png","sheet_x":22,"sheet_y":39,"short_name":"loud_sound","short_names":["loud_sound"],"text":null,"texts":null,"category":"Symbols","sort_order":229,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BATTERY","unified":"1F50B","variations":[],"docomo":null,"au":"E584","softbank":null,"google":"FE4FC","image":"1f50b.png","sheet_x":22,"sheet_y":40,"short_name":"battery","short_names":["battery"],"text":null,"texts":null,"category":"Objects","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ELECTRIC PLUG","unified":"1F50C","variations":[],"docomo":null,"au":"E589","softbank":null,"google":"FE4FE","image":"1f50c.png","sheet_x":23,"sheet_y":0,"short_name":"electric_plug","short_names":["electric_plug"],"text":null,"texts":null,"category":"Objects","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFT-POINTING MAGNIFYING GLASS","unified":"1F50D","variations":[],"docomo":"E6DC","au":"E518","softbank":"E114","google":"FEB85","image":"1f50d.png","sheet_x":23,"sheet_y":1,"short_name":"mag","short_names":["mag"],"text":null,"texts":null,"category":"Objects","sort_order":177,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RIGHT-POINTING MAGNIFYING GLASS","unified":"1F50E","variations":[],"docomo":"E6DC","au":"EB05","softbank":"E114","google":"FEB8D","image":"1f50e.png","sheet_x":23,"sheet_y":2,"short_name":"mag_right","short_names":["mag_right"],"text":null,"texts":null,"category":"Objects","sort_order":178,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOCK WITH INK PEN","unified":"1F50F","variations":[],"docomo":"E6D9","au":"EB0C","softbank":"E144","google":"FEB90","image":"1f50f.png","sheet_x":23,"sheet_y":3,"short_name":"lock_with_ink_pen","short_names":["lock_with_ink_pen"],"text":null,"texts":null,"category":"Objects","sort_order":169,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOSED LOCK WITH KEY","unified":"1F510","variations":[],"docomo":"E6D9","au":"EAFC","softbank":"E144","google":"FEB8A","image":"1f510.png","sheet_x":23,"sheet_y":4,"short_name":"closed_lock_with_key","short_names":["closed_lock_with_key"],"text":null,"texts":null,"category":"Objects","sort_order":166,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEY","unified":"1F511","variations":[],"docomo":"E6D9","au":"E519","softbank":"E03F","google":"FEB82","image":"1f511.png","sheet_x":23,"sheet_y":5,"short_name":"key","short_names":["key"],"text":null,"texts":null,"category":"Objects","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOCK","unified":"1F512","variations":[],"docomo":"E6D9","au":"E51C","softbank":"E144","google":"FEB86","image":"1f512.png","sheet_x":23,"sheet_y":6,"short_name":"lock","short_names":["lock"],"text":null,"texts":null,"category":"Objects","sort_order":167,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OPEN LOCK","unified":"1F513","variations":[],"docomo":"E6D9","au":"E51C","softbank":"E145","google":"FEB87","image":"1f513.png","sheet_x":23,"sheet_y":7,"short_name":"unlock","short_names":["unlock"],"text":null,"texts":null,"category":"Objects","sort_order":168,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BELL","unified":"1F514","variations":[],"docomo":"E713","au":"E512","softbank":"E325","google":"FE4F2","image":"1f514.png","sheet_x":23,"sheet_y":8,"short_name":"bell","short_names":["bell"],"text":null,"texts":null,"category":"Symbols","sort_order":233,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BELL WITH CANCELLATION STROKE","unified":"1F515","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f515.png","sheet_x":23,"sheet_y":9,"short_name":"no_bell","short_names":["no_bell"],"text":null,"texts":null,"category":"Symbols","sort_order":234,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BOOKMARK","unified":"1F516","variations":[],"docomo":null,"au":"EB07","softbank":null,"google":"FEB8F","image":"1f516.png","sheet_x":23,"sheet_y":10,"short_name":"bookmark","short_names":["bookmark"],"text":null,"texts":null,"category":"Objects","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LINK SYMBOL","unified":"1F517","variations":[],"docomo":null,"au":"E58A","softbank":null,"google":"FEB4B","image":"1f517.png","sheet_x":23,"sheet_y":11,"short_name":"link","short_names":["link"],"text":null,"texts":null,"category":"Objects","sort_order":155,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RADIO BUTTON","unified":"1F518","variations":[],"docomo":null,"au":"EB04","softbank":null,"google":"FEB8C","image":"1f518.png","sheet_x":23,"sheet_y":12,"short_name":"radio_button","short_names":["radio_button"],"text":null,"texts":null,"category":"Symbols","sort_order":206,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BACK WITH LEFTWARDS ARROW ABOVE","unified":"1F519","variations":[],"docomo":null,"au":"EB06","softbank":"E235","google":"FEB8E","image":"1f519.png","sheet_x":23,"sheet_y":13,"short_name":"back","short_names":["back"],"text":null,"texts":null,"category":"Symbols","sort_order":201,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"END WITH LEFTWARDS ARROW ABOVE","unified":"1F51A","variations":[],"docomo":"E6B9","au":null,"softbank":null,"google":"FE01A","image":"1f51a.png","sheet_x":23,"sheet_y":14,"short_name":"end","short_names":["end"],"text":null,"texts":null,"category":"Symbols","sort_order":200,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE","unified":"1F51B","variations":[],"docomo":"E6B8","au":null,"softbank":null,"google":"FE019","image":"1f51b.png","sheet_x":23,"sheet_y":15,"short_name":"on","short_names":["on"],"text":null,"texts":null,"category":"Symbols","sort_order":202,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SOON WITH RIGHTWARDS ARROW ABOVE","unified":"1F51C","variations":[],"docomo":"E6B7","au":null,"softbank":null,"google":"FE018","image":"1f51c.png","sheet_x":23,"sheet_y":16,"short_name":"soon","short_names":["soon"],"text":null,"texts":null,"category":"Symbols","sort_order":204,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TOP WITH UPWARDS ARROW ABOVE","unified":"1F51D","variations":[],"docomo":null,"au":null,"softbank":"E24C","google":"FEB42","image":"1f51d.png","sheet_x":23,"sheet_y":17,"short_name":"top","short_names":["top"],"text":null,"texts":null,"category":"Symbols","sort_order":203,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO ONE UNDER EIGHTEEN SYMBOL","unified":"1F51E","variations":[],"docomo":null,"au":"EA83","softbank":"E207","google":"FEB25","image":"1f51e.png","sheet_x":23,"sheet_y":18,"short_name":"underage","short_names":["underage"],"text":null,"texts":null,"category":"Symbols","sort_order":80,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP TEN","unified":"1F51F","variations":[],"docomo":null,"au":"E52B","softbank":null,"google":"FE83B","image":"1f51f.png","sheet_x":23,"sheet_y":19,"short_name":"keycap_ten","short_names":["keycap_ten"],"text":null,"texts":null,"category":"Symbols","sort_order":144,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INPUT SYMBOL FOR LATIN CAPITAL LETTERS","unified":"1F520","variations":[],"docomo":null,"au":"EAFD","softbank":null,"google":"FEB7C","image":"1f520.png","sheet_x":23,"sheet_y":20,"short_name":"capital_abcd","short_names":["capital_abcd"],"text":null,"texts":null,"category":"Symbols","sort_order":183,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INPUT SYMBOL FOR LATIN SMALL LETTERS","unified":"1F521","variations":[],"docomo":null,"au":"EAFE","softbank":null,"google":"FEB7D","image":"1f521.png","sheet_x":23,"sheet_y":21,"short_name":"abcd","short_names":["abcd"],"text":null,"texts":null,"category":"Symbols","sort_order":182,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INPUT SYMBOL FOR NUMBERS","unified":"1F522","variations":[],"docomo":null,"au":"EAFF","softbank":null,"google":"FEB7E","image":"1f522.png","sheet_x":23,"sheet_y":22,"short_name":"1234","short_names":["1234"],"text":null,"texts":null,"category":"Symbols","sort_order":145,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INPUT SYMBOL FOR SYMBOLS","unified":"1F523","variations":[],"docomo":null,"au":"EB00","softbank":null,"google":"FEB7F","image":"1f523.png","sheet_x":23,"sheet_y":23,"short_name":"symbols","short_names":["symbols"],"text":null,"texts":null,"category":"Symbols","sort_order":184,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"INPUT SYMBOL FOR LATIN LETTERS","unified":"1F524","variations":[],"docomo":null,"au":"EB55","softbank":null,"google":"FEB80","image":"1f524.png","sheet_x":23,"sheet_y":24,"short_name":"abc","short_names":["abc"],"text":null,"texts":null,"category":"Symbols","sort_order":181,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIRE","unified":"1F525","variations":[],"docomo":null,"au":"E47B","softbank":"E11D","google":"FE4F6","image":"1f525.png","sheet_x":23,"sheet_y":25,"short_name":"fire","short_names":["fire"],"text":null,"texts":null,"category":"Nature","sort_order":133,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ELECTRIC TORCH","unified":"1F526","variations":[],"docomo":"E6FB","au":"E583","softbank":null,"google":"FE4FB","image":"1f526.png","sheet_x":23,"sheet_y":26,"short_name":"flashlight","short_names":["flashlight"],"text":null,"texts":null,"category":"Objects","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WRENCH","unified":"1F527","variations":[],"docomo":"E718","au":"E587","softbank":null,"google":"FE4C9","image":"1f527.png","sheet_x":23,"sheet_y":27,"short_name":"wrench","short_names":["wrench"],"text":null,"texts":null,"category":"Objects","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAMMER","unified":"1F528","variations":[],"docomo":null,"au":"E5CB","softbank":"E116","google":"FE4CA","image":"1f528.png","sheet_x":23,"sheet_y":28,"short_name":"hammer","short_names":["hammer"],"text":null,"texts":null,"category":"Objects","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NUT AND BOLT","unified":"1F529","variations":[],"docomo":null,"au":"E581","softbank":null,"google":"FE4CB","image":"1f529.png","sheet_x":23,"sheet_y":29,"short_name":"nut_and_bolt","short_names":["nut_and_bolt"],"text":null,"texts":null,"category":"Objects","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOCHO","unified":"1F52A","variations":[],"docomo":null,"au":"E57F","softbank":null,"google":"FE4FA","image":"1f52a.png","sheet_x":23,"sheet_y":30,"short_name":"hocho","short_names":["hocho","knife"],"text":null,"texts":null,"category":"Objects","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PISTOL","unified":"1F52B","variations":[],"docomo":null,"au":"E50A","softbank":"E113","google":"FE4F5","image":"1f52b.png","sheet_x":23,"sheet_y":31,"short_name":"gun","short_names":["gun"],"text":null,"texts":null,"category":"Objects","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MICROSCOPE","unified":"1F52C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f52c.png","sheet_x":23,"sheet_y":32,"short_name":"microscope","short_names":["microscope"],"text":null,"texts":null,"category":"Objects","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TELESCOPE","unified":"1F52D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f52d.png","sheet_x":23,"sheet_y":33,"short_name":"telescope","short_names":["telescope"],"text":null,"texts":null,"category":"Objects","sort_order":78,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CRYSTAL BALL","unified":"1F52E","variations":[],"docomo":null,"au":"EA8F","softbank":"E23E","google":"FE4F7","image":"1f52e.png","sheet_x":23,"sheet_y":34,"short_name":"crystal_ball","short_names":["crystal_ball"],"text":null,"texts":null,"category":"Objects","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SIX POINTED STAR WITH MIDDLE DOT","unified":"1F52F","variations":[],"docomo":null,"au":"EA8F","softbank":"E23E","google":"FE4F8","image":"1f52f.png","sheet_x":23,"sheet_y":35,"short_name":"six_pointed_star","short_names":["six_pointed_star"],"text":null,"texts":null,"category":"Symbols","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JAPANESE SYMBOL FOR BEGINNER","unified":"1F530","variations":[],"docomo":null,"au":"E480","softbank":"E209","google":"FE044","image":"1f530.png","sheet_x":23,"sheet_y":36,"short_name":"beginner","short_names":["beginner"],"text":null,"texts":null,"category":"Symbols","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRIDENT EMBLEM","unified":"1F531","variations":[],"docomo":"E71A","au":"E5C9","softbank":"E031","google":"FE4D2","image":"1f531.png","sheet_x":23,"sheet_y":37,"short_name":"trident","short_names":["trident"],"text":null,"texts":null,"category":"Symbols","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BLACK SQUARE BUTTON","unified":"1F532","variations":[],"docomo":"E69C","au":"E54B","softbank":"E21A","google":"FEB64","image":"1f532.png","sheet_x":23,"sheet_y":38,"short_name":"black_square_button","short_names":["black_square_button"],"text":null,"texts":null,"category":"Symbols","sort_order":225,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WHITE SQUARE BUTTON","unified":"1F533","variations":[],"docomo":"E69C","au":"E54B","softbank":"E21B","google":"FEB67","image":"1f533.png","sheet_x":23,"sheet_y":39,"short_name":"white_square_button","short_names":["white_square_button"],"text":null,"texts":null,"category":"Symbols","sort_order":226,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LARGE RED CIRCLE","unified":"1F534","variations":[],"docomo":"E69C","au":"E54A","softbank":"E219","google":"FEB63","image":"1f534.png","sheet_x":23,"sheet_y":40,"short_name":"red_circle","short_names":["red_circle"],"text":null,"texts":null,"category":"Symbols","sort_order":209,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LARGE BLUE CIRCLE","unified":"1F535","variations":[],"docomo":"E69C","au":"E54B","softbank":"E21A","google":"FEB64","image":"1f535.png","sheet_x":24,"sheet_y":0,"short_name":"large_blue_circle","short_names":["large_blue_circle"],"text":null,"texts":null,"category":"Symbols","sort_order":210,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LARGE ORANGE DIAMOND","unified":"1F536","variations":[],"docomo":null,"au":"E546","softbank":"E21B","google":"FEB73","image":"1f536.png","sheet_x":24,"sheet_y":1,"short_name":"large_orange_diamond","short_names":["large_orange_diamond"],"text":null,"texts":null,"category":"Symbols","sort_order":213,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LARGE BLUE DIAMOND","unified":"1F537","variations":[],"docomo":null,"au":"E547","softbank":"E21B","google":"FEB74","image":"1f537.png","sheet_x":24,"sheet_y":2,"short_name":"large_blue_diamond","short_names":["large_blue_diamond"],"text":null,"texts":null,"category":"Symbols","sort_order":214,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMALL ORANGE DIAMOND","unified":"1F538","variations":[],"docomo":null,"au":"E536","softbank":"E21B","google":"FEB75","image":"1f538.png","sheet_x":24,"sheet_y":3,"short_name":"small_orange_diamond","short_names":["small_orange_diamond"],"text":null,"texts":null,"category":"Symbols","sort_order":211,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMALL BLUE DIAMOND","unified":"1F539","variations":[],"docomo":null,"au":"E537","softbank":"E21B","google":"FEB76","image":"1f539.png","sheet_x":24,"sheet_y":4,"short_name":"small_blue_diamond","short_names":["small_blue_diamond"],"text":null,"texts":null,"category":"Symbols","sort_order":212,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UP-POINTING RED TRIANGLE","unified":"1F53A","variations":[],"docomo":null,"au":"E55A","softbank":null,"google":"FEB78","image":"1f53a.png","sheet_x":24,"sheet_y":5,"short_name":"small_red_triangle","short_names":["small_red_triangle"],"text":null,"texts":null,"category":"Symbols","sort_order":215,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOWN-POINTING RED TRIANGLE","unified":"1F53B","variations":[],"docomo":null,"au":"E55B","softbank":null,"google":"FEB79","image":"1f53b.png","sheet_x":24,"sheet_y":6,"short_name":"small_red_triangle_down","short_names":["small_red_triangle_down"],"text":null,"texts":null,"category":"Symbols","sort_order":220,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UP-POINTING SMALL RED TRIANGLE","unified":"1F53C","variations":[],"docomo":null,"au":"E543","softbank":null,"google":"FEB01","image":"1f53c.png","sheet_x":24,"sheet_y":7,"short_name":"arrow_up_small","short_names":["arrow_up_small"],"text":null,"texts":null,"category":"Symbols","sort_order":159,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOWN-POINTING SMALL RED TRIANGLE","unified":"1F53D","variations":[],"docomo":null,"au":"E542","softbank":null,"google":"FEB00","image":"1f53d.png","sheet_x":24,"sheet_y":8,"short_name":"arrow_down_small","short_names":["arrow_down_small"],"text":null,"texts":null,"category":"Symbols","sort_order":160,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OM SYMBOL","unified":"1F549","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f549.png","sheet_x":24,"sheet_y":9,"short_name":"om_symbol","short_names":["om_symbol"],"text":null,"texts":null,"category":"Symbols","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOVE OF PEACE","unified":"1F54A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f54a.png","sheet_x":24,"sheet_y":10,"short_name":"dove_of_peace","short_names":["dove_of_peace"],"text":null,"texts":null,"category":"Nature","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KAABA","unified":"1F54B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f54b.png","sheet_x":24,"sheet_y":11,"short_name":"kaaba","short_names":["kaaba"],"text":null,"texts":null,"category":"Places","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOSQUE","unified":"1F54C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f54c.png","sheet_x":24,"sheet_y":12,"short_name":"mosque","short_names":["mosque"],"text":null,"texts":null,"category":"Places","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SYNAGOGUE","unified":"1F54D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f54d.png","sheet_x":24,"sheet_y":13,"short_name":"synagogue","short_names":["synagogue"],"text":null,"texts":null,"category":"Places","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MENORAH WITH NINE BRANCHES","unified":"1F54E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f54e.png","sheet_x":24,"sheet_y":14,"short_name":"menorah_with_nine_branches","short_names":["menorah_with_nine_branches"],"text":null,"texts":null,"category":"Symbols","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE ONE OCLOCK","unified":"1F550","variations":[],"docomo":"E6BA","au":"E594","softbank":"E024","google":"FE01E","image":"1f550.png","sheet_x":24,"sheet_y":15,"short_name":"clock1","short_names":["clock1"],"text":null,"texts":null,"category":"Symbols","sort_order":246,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TWO OCLOCK","unified":"1F551","variations":[],"docomo":"E6BA","au":"E594","softbank":"E025","google":"FE01F","image":"1f551.png","sheet_x":24,"sheet_y":16,"short_name":"clock2","short_names":["clock2"],"text":null,"texts":null,"category":"Symbols","sort_order":247,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE THREE OCLOCK","unified":"1F552","variations":[],"docomo":"E6BA","au":"E594","softbank":"E026","google":"FE020","image":"1f552.png","sheet_x":24,"sheet_y":17,"short_name":"clock3","short_names":["clock3"],"text":null,"texts":null,"category":"Symbols","sort_order":248,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE FOUR OCLOCK","unified":"1F553","variations":[],"docomo":"E6BA","au":"E594","softbank":"E027","google":"FE021","image":"1f553.png","sheet_x":24,"sheet_y":18,"short_name":"clock4","short_names":["clock4"],"text":null,"texts":null,"category":"Symbols","sort_order":249,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE FIVE OCLOCK","unified":"1F554","variations":[],"docomo":"E6BA","au":"E594","softbank":"E028","google":"FE022","image":"1f554.png","sheet_x":24,"sheet_y":19,"short_name":"clock5","short_names":["clock5"],"text":null,"texts":null,"category":"Symbols","sort_order":250,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE SIX OCLOCK","unified":"1F555","variations":[],"docomo":"E6BA","au":"E594","softbank":"E029","google":"FE023","image":"1f555.png","sheet_x":24,"sheet_y":20,"short_name":"clock6","short_names":["clock6"],"text":null,"texts":null,"category":"Symbols","sort_order":251,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE SEVEN OCLOCK","unified":"1F556","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02A","google":"FE024","image":"1f556.png","sheet_x":24,"sheet_y":21,"short_name":"clock7","short_names":["clock7"],"text":null,"texts":null,"category":"Symbols","sort_order":252,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE EIGHT OCLOCK","unified":"1F557","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02B","google":"FE025","image":"1f557.png","sheet_x":24,"sheet_y":22,"short_name":"clock8","short_names":["clock8"],"text":null,"texts":null,"category":"Symbols","sort_order":253,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE NINE OCLOCK","unified":"1F558","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02C","google":"FE026","image":"1f558.png","sheet_x":24,"sheet_y":23,"short_name":"clock9","short_names":["clock9"],"text":null,"texts":null,"category":"Symbols","sort_order":254,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TEN OCLOCK","unified":"1F559","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02D","google":"FE027","image":"1f559.png","sheet_x":24,"sheet_y":24,"short_name":"clock10","short_names":["clock10"],"text":null,"texts":null,"category":"Symbols","sort_order":255,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE ELEVEN OCLOCK","unified":"1F55A","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02E","google":"FE028","image":"1f55a.png","sheet_x":24,"sheet_y":25,"short_name":"clock11","short_names":["clock11"],"text":null,"texts":null,"category":"Symbols","sort_order":256,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TWELVE OCLOCK","unified":"1F55B","variations":[],"docomo":"E6BA","au":"E594","softbank":"E02F","google":"FE029","image":"1f55b.png","sheet_x":24,"sheet_y":26,"short_name":"clock12","short_names":["clock12"],"text":null,"texts":null,"category":"Symbols","sort_order":257,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE ONE-THIRTY","unified":"1F55C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f55c.png","sheet_x":24,"sheet_y":27,"short_name":"clock130","short_names":["clock130"],"text":null,"texts":null,"category":"Symbols","sort_order":258,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TWO-THIRTY","unified":"1F55D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f55d.png","sheet_x":24,"sheet_y":28,"short_name":"clock230","short_names":["clock230"],"text":null,"texts":null,"category":"Symbols","sort_order":259,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE THREE-THIRTY","unified":"1F55E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f55e.png","sheet_x":24,"sheet_y":29,"short_name":"clock330","short_names":["clock330"],"text":null,"texts":null,"category":"Symbols","sort_order":260,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE FOUR-THIRTY","unified":"1F55F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f55f.png","sheet_x":24,"sheet_y":30,"short_name":"clock430","short_names":["clock430"],"text":null,"texts":null,"category":"Symbols","sort_order":261,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE FIVE-THIRTY","unified":"1F560","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f560.png","sheet_x":24,"sheet_y":31,"short_name":"clock530","short_names":["clock530"],"text":null,"texts":null,"category":"Symbols","sort_order":262,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE SIX-THIRTY","unified":"1F561","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f561.png","sheet_x":24,"sheet_y":32,"short_name":"clock630","short_names":["clock630"],"text":null,"texts":null,"category":"Symbols","sort_order":263,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE SEVEN-THIRTY","unified":"1F562","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f562.png","sheet_x":24,"sheet_y":33,"short_name":"clock730","short_names":["clock730"],"text":null,"texts":null,"category":"Symbols","sort_order":264,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE EIGHT-THIRTY","unified":"1F563","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f563.png","sheet_x":24,"sheet_y":34,"short_name":"clock830","short_names":["clock830"],"text":null,"texts":null,"category":"Symbols","sort_order":265,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE NINE-THIRTY","unified":"1F564","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f564.png","sheet_x":24,"sheet_y":35,"short_name":"clock930","short_names":["clock930"],"text":null,"texts":null,"category":"Symbols","sort_order":266,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TEN-THIRTY","unified":"1F565","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f565.png","sheet_x":24,"sheet_y":36,"short_name":"clock1030","short_names":["clock1030"],"text":null,"texts":null,"category":"Symbols","sort_order":267,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE ELEVEN-THIRTY","unified":"1F566","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f566.png","sheet_x":24,"sheet_y":37,"short_name":"clock1130","short_names":["clock1130"],"text":null,"texts":null,"category":"Symbols","sort_order":268,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CLOCK FACE TWELVE-THIRTY","unified":"1F567","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f567.png","sheet_x":24,"sheet_y":38,"short_name":"clock1230","short_names":["clock1230"],"text":null,"texts":null,"category":"Symbols","sort_order":269,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CANDLE","unified":"1F56F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f56f.png","sheet_x":24,"sheet_y":39,"short_name":"candle","short_names":["candle"],"text":null,"texts":null,"category":"Objects","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MANTELPIECE CLOCK","unified":"1F570","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f570.png","sheet_x":24,"sheet_y":40,"short_name":"mantelpiece_clock","short_names":["mantelpiece_clock"],"text":null,"texts":null,"category":"Objects","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HOLE","unified":"1F573","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f573.png","sheet_x":25,"sheet_y":0,"short_name":"hole","short_names":["hole"],"text":null,"texts":null,"category":"Objects","sort_order":80,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MAN IN BUSINESS SUIT LEVITATING","unified":"1F574","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f574.png","sheet_x":25,"sheet_y":1,"short_name":"man_in_business_suit_levitating","short_names":["man_in_business_suit_levitating"],"text":null,"texts":null,"category":"Activity","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLEUTH OR SPY","unified":"1F575","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f575.png","sheet_x":25,"sheet_y":2,"short_name":"sleuth_or_spy","short_names":["sleuth_or_spy"],"text":null,"texts":null,"category":"People","sort_order":134,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DARK SUNGLASSES","unified":"1F576","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f576.png","sheet_x":25,"sheet_y":3,"short_name":"dark_sunglasses","short_names":["dark_sunglasses"],"text":null,"texts":null,"category":"People","sort_order":202,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPIDER","unified":"1F577","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f577.png","sheet_x":25,"sheet_y":4,"short_name":"spider","short_names":["spider"],"text":null,"texts":null,"category":"Nature","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPIDER WEB","unified":"1F578","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f578.png","sheet_x":25,"sheet_y":5,"short_name":"spider_web","short_names":["spider_web"],"text":null,"texts":null,"category":"Nature","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"JOYSTICK","unified":"1F579","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f579.png","sheet_x":25,"sheet_y":6,"short_name":"joystick","short_names":["joystick"],"text":null,"texts":null,"category":"Objects","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LINKED PAPERCLIPS","unified":"1F587","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f587.png","sheet_x":25,"sheet_y":7,"short_name":"linked_paperclips","short_names":["linked_paperclips"],"text":null,"texts":null,"category":"Objects","sort_order":157,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOWER LEFT BALLPOINT PEN","unified":"1F58A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f58a.png","sheet_x":25,"sheet_y":8,"short_name":"lower_left_ballpoint_pen","short_names":["lower_left_ballpoint_pen"],"text":null,"texts":null,"category":"Objects","sort_order":170,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOWER LEFT FOUNTAIN PEN","unified":"1F58B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f58b.png","sheet_x":25,"sheet_y":9,"short_name":"lower_left_fountain_pen","short_names":["lower_left_fountain_pen"],"text":null,"texts":null,"category":"Objects","sort_order":171,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOWER LEFT PAINTBRUSH","unified":"1F58C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f58c.png","sheet_x":25,"sheet_y":10,"short_name":"lower_left_paintbrush","short_names":["lower_left_paintbrush"],"text":null,"texts":null,"category":"Objects","sort_order":176,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOWER LEFT CRAYON","unified":"1F58D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f58d.png","sheet_x":25,"sheet_y":11,"short_name":"lower_left_crayon","short_names":["lower_left_crayon"],"text":null,"texts":null,"category":"Objects","sort_order":175,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAISED HAND WITH FINGERS SPLAYED","unified":"1F590","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f590.png","sheet_x":25,"sheet_y":12,"short_name":"raised_hand_with_fingers_splayed","short_names":["raised_hand_with_fingers_splayed"],"text":null,"texts":null,"category":"People","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F590-1F3FB":{"unified":"1F590-1F3FB","image":"1f590-1f3fb.png","sheet_x":25,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F590-1F3FC":{"unified":"1F590-1F3FC","image":"1f590-1f3fc.png","sheet_x":25,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F590-1F3FD":{"unified":"1F590-1F3FD","image":"1f590-1f3fd.png","sheet_x":25,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F590-1F3FE":{"unified":"1F590-1F3FE","image":"1f590-1f3fe.png","sheet_x":25,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F590-1F3FF":{"unified":"1F590-1F3FF","image":"1f590-1f3ff.png","sheet_x":25,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"REVERSED HAND WITH MIDDLE FINGER EXTENDED","unified":"1F595","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f595.png","sheet_x":25,"sheet_y":18,"short_name":"middle_finger","short_names":["middle_finger","reversed_hand_with_middle_finger_extended"],"text":null,"texts":null,"category":"People","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F595-1F3FB":{"unified":"1F595-1F3FB","image":"1f595-1f3fb.png","sheet_x":25,"sheet_y":19,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F595-1F3FC":{"unified":"1F595-1F3FC","image":"1f595-1f3fc.png","sheet_x":25,"sheet_y":20,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F595-1F3FD":{"unified":"1F595-1F3FD","image":"1f595-1f3fd.png","sheet_x":25,"sheet_y":21,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F595-1F3FE":{"unified":"1F595-1F3FE","image":"1f595-1f3fe.png","sheet_x":25,"sheet_y":22,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F595-1F3FF":{"unified":"1F595-1F3FF","image":"1f595-1f3ff.png","sheet_x":25,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS","unified":"1F596","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f596.png","sheet_x":25,"sheet_y":24,"short_name":"spock-hand","short_names":["spock-hand"],"text":null,"texts":null,"category":"People","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F596-1F3FB":{"unified":"1F596-1F3FB","image":"1f596-1f3fb.png","sheet_x":25,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F596-1F3FC":{"unified":"1F596-1F3FC","image":"1f596-1f3fc.png","sheet_x":25,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F596-1F3FD":{"unified":"1F596-1F3FD","image":"1f596-1f3fd.png","sheet_x":25,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F596-1F3FE":{"unified":"1F596-1F3FE","image":"1f596-1f3fe.png","sheet_x":25,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F596-1F3FF":{"unified":"1F596-1F3FF","image":"1f596-1f3ff.png","sheet_x":25,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"DESKTOP COMPUTER","unified":"1F5A5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5a5.png","sheet_x":25,"sheet_y":30,"short_name":"desktop_computer","short_names":["desktop_computer"],"text":null,"texts":null,"category":"Objects","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PRINTER","unified":"1F5A8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5a8.png","sheet_x":25,"sheet_y":31,"short_name":"printer","short_names":["printer"],"text":null,"texts":null,"category":"Objects","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"THREE BUTTON MOUSE","unified":"1F5B1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5b1.png","sheet_x":25,"sheet_y":32,"short_name":"three_button_mouse","short_names":["three_button_mouse"],"text":null,"texts":null,"category":"Objects","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRACKBALL","unified":"1F5B2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5b2.png","sheet_x":25,"sheet_y":33,"short_name":"trackball","short_names":["trackball"],"text":null,"texts":null,"category":"Objects","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FRAME WITH PICTURE","unified":"1F5BC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5bc.png","sheet_x":25,"sheet_y":34,"short_name":"frame_with_picture","short_names":["frame_with_picture"],"text":null,"texts":null,"category":"Objects","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CARD INDEX DIVIDERS","unified":"1F5C2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5c2.png","sheet_x":25,"sheet_y":35,"short_name":"card_index_dividers","short_names":["card_index_dividers"],"text":null,"texts":null,"category":"Objects","sort_order":143,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CARD FILE BOX","unified":"1F5C3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5c3.png","sheet_x":25,"sheet_y":36,"short_name":"card_file_box","short_names":["card_file_box"],"text":null,"texts":null,"category":"Objects","sort_order":136,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FILE CABINET","unified":"1F5C4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5c4.png","sheet_x":25,"sheet_y":37,"short_name":"file_cabinet","short_names":["file_cabinet"],"text":null,"texts":null,"category":"Objects","sort_order":138,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WASTEBASKET","unified":"1F5D1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5d1.png","sheet_x":25,"sheet_y":38,"short_name":"wastebasket","short_names":["wastebasket"],"text":null,"texts":null,"category":"Objects","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPIRAL NOTE PAD","unified":"1F5D2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5d2.png","sheet_x":25,"sheet_y":39,"short_name":"spiral_note_pad","short_names":["spiral_note_pad"],"text":null,"texts":null,"category":"Objects","sort_order":140,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPIRAL CALENDAR PAD","unified":"1F5D3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5d3.png","sheet_x":25,"sheet_y":40,"short_name":"spiral_calendar_pad","short_names":["spiral_calendar_pad"],"text":null,"texts":null,"category":"Objects","sort_order":134,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COMPRESSION","unified":"1F5DC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5dc.png","sheet_x":26,"sheet_y":0,"short_name":"compression","short_names":["compression"],"text":null,"texts":null,"category":"Objects","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OLD KEY","unified":"1F5DD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5dd.png","sheet_x":26,"sheet_y":1,"short_name":"old_key","short_names":["old_key"],"text":null,"texts":null,"category":"Objects","sort_order":90,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROLLED-UP NEWSPAPER","unified":"1F5DE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5de.png","sheet_x":26,"sheet_y":2,"short_name":"rolled_up_newspaper","short_names":["rolled_up_newspaper"],"text":null,"texts":null,"category":"Objects","sort_order":144,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DAGGER KNIFE","unified":"1F5E1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5e1.png","sheet_x":26,"sheet_y":3,"short_name":"dagger_knife","short_names":["dagger_knife"],"text":null,"texts":null,"category":"Objects","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAKING HEAD IN SILHOUETTE","unified":"1F5E3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5e3.png","sheet_x":26,"sheet_y":4,"short_name":"speaking_head_in_silhouette","short_names":["speaking_head_in_silhouette"],"text":null,"texts":null,"category":"People","sort_order":120,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFT SPEECH BUBBLE","unified":"1F5E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5e8.png","sheet_x":26,"sheet_y":5,"short_name":"left_speech_bubble","short_names":["left_speech_bubble"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":false},{"name":"RIGHT ANGER BUBBLE","unified":"1F5EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5ef.png","sheet_x":26,"sheet_y":6,"short_name":"right_anger_bubble","short_names":["right_anger_bubble"],"text":null,"texts":null,"category":"Symbols","sort_order":244,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BALLOT BOX WITH BALLOT","unified":"1F5F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5f3.png","sheet_x":26,"sheet_y":7,"short_name":"ballot_box_with_ballot","short_names":["ballot_box_with_ballot"],"text":null,"texts":null,"category":"Objects","sort_order":137,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WORLD MAP","unified":"1F5FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f5fa.png","sheet_x":26,"sheet_y":8,"short_name":"world_map","short_names":["world_map"],"text":null,"texts":null,"category":"Objects","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUNT FUJI","unified":"1F5FB","variations":[],"docomo":"E740","au":"E5BD","softbank":"E03B","google":"FE4C3","image":"1f5fb.png","sheet_x":26,"sheet_y":9,"short_name":"mount_fuji","short_names":["mount_fuji"],"text":null,"texts":null,"category":"Places","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TOKYO TOWER","unified":"1F5FC","variations":[],"docomo":null,"au":"E4C0","softbank":"E509","google":"FE4C4","image":"1f5fc.png","sheet_x":26,"sheet_y":10,"short_name":"tokyo_tower","short_names":["tokyo_tower"],"text":null,"texts":null,"category":"Places","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STATUE OF LIBERTY","unified":"1F5FD","variations":[],"docomo":null,"au":null,"softbank":"E51D","google":"FE4C6","image":"1f5fd.png","sheet_x":26,"sheet_y":11,"short_name":"statue_of_liberty","short_names":["statue_of_liberty"],"text":null,"texts":null,"category":"Places","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SILHOUETTE OF JAPAN","unified":"1F5FE","variations":[],"docomo":null,"au":"E572","softbank":null,"google":"FE4C7","image":"1f5fe.png","sheet_x":26,"sheet_y":12,"short_name":"japan","short_names":["japan"],"text":null,"texts":null,"category":"Places","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOYAI","unified":"1F5FF","variations":[],"docomo":null,"au":"EB6C","softbank":null,"google":"FE4C8","image":"1f5ff.png","sheet_x":26,"sheet_y":13,"short_name":"moyai","short_names":["moyai"],"text":null,"texts":null,"category":"Objects","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRINNING FACE","unified":"1F600","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f600.png","sheet_x":26,"sheet_y":14,"short_name":"grinning","short_names":["grinning"],"text":":D","texts":null,"category":"People","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRINNING FACE WITH SMILING EYES","unified":"1F601","variations":[],"docomo":"E753","au":"EB80","softbank":"E404","google":"FE333","image":"1f601.png","sheet_x":26,"sheet_y":15,"short_name":"grin","short_names":["grin"],"text":null,"texts":null,"category":"People","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH TEARS OF JOY","unified":"1F602","variations":[],"docomo":"E72A","au":"EB64","softbank":"E412","google":"FE334","image":"1f602.png","sheet_x":26,"sheet_y":16,"short_name":"joy","short_names":["joy"],"text":null,"texts":null,"category":"People","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH OPEN MOUTH","unified":"1F603","variations":[],"docomo":"E6F0","au":"E471","softbank":"E057","google":"FE330","image":"1f603.png","sheet_x":26,"sheet_y":17,"short_name":"smiley","short_names":["smiley"],"text":":)","texts":["=)","=-)"],"category":"People","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH OPEN MOUTH AND SMILING EYES","unified":"1F604","variations":[],"docomo":"E6F0","au":"E471","softbank":"E415","google":"FE338","image":"1f604.png","sheet_x":26,"sheet_y":18,"short_name":"smile","short_names":["smile"],"text":":)","texts":["C:","c:",":D",":-D"],"category":"People","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH OPEN MOUTH AND COLD SWEAT","unified":"1F605","variations":[],"docomo":"E722","au":"E471-E5B1","softbank":"E415-E331","google":"FE331","image":"1f605.png","sheet_x":26,"sheet_y":19,"short_name":"sweat_smile","short_names":["sweat_smile"],"text":null,"texts":null,"category":"People","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES","unified":"1F606","variations":[],"docomo":"E72A","au":"EAC5","softbank":"E40A","google":"FE332","image":"1f606.png","sheet_x":26,"sheet_y":20,"short_name":"laughing","short_names":["laughing","satisfied"],"text":null,"texts":[":>",":->"],"category":"People","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH HALO","unified":"1F607","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f607.png","sheet_x":26,"sheet_y":21,"short_name":"innocent","short_names":["innocent"],"text":null,"texts":null,"category":"People","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH HORNS","unified":"1F608","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f608.png","sheet_x":26,"sheet_y":22,"short_name":"smiling_imp","short_names":["smiling_imp"],"text":null,"texts":null,"category":"People","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WINKING FACE","unified":"1F609","variations":[],"docomo":"E729","au":"E5C3","softbank":"E405","google":"FE347","image":"1f609.png","sheet_x":26,"sheet_y":23,"short_name":"wink","short_names":["wink"],"text":";)","texts":[";)",";-)"],"category":"People","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH SMILING EYES","unified":"1F60A","variations":[],"docomo":"E6F0","au":"EACD","softbank":"E056","google":"FE335","image":"1f60a.png","sheet_x":26,"sheet_y":24,"short_name":"blush","short_names":["blush"],"text":":)","texts":[":)","(:",":-)"],"category":"People","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE SAVOURING DELICIOUS FOOD","unified":"1F60B","variations":[],"docomo":"E752","au":"EACD","softbank":"E056","google":"FE32B","image":"1f60b.png","sheet_x":26,"sheet_y":25,"short_name":"yum","short_names":["yum"],"text":null,"texts":null,"category":"People","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RELIEVED FACE","unified":"1F60C","variations":[],"docomo":"E721","au":"EAC5","softbank":"E40A","google":"FE33E","image":"1f60c.png","sheet_x":26,"sheet_y":26,"short_name":"relieved","short_names":["relieved"],"text":null,"texts":null,"category":"People","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH HEART-SHAPED EYES","unified":"1F60D","variations":[],"docomo":"E726","au":"E5C4","softbank":"E106","google":"FE327","image":"1f60d.png","sheet_x":26,"sheet_y":27,"short_name":"heart_eyes","short_names":["heart_eyes"],"text":null,"texts":null,"category":"People","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING FACE WITH SUNGLASSES","unified":"1F60E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f60e.png","sheet_x":26,"sheet_y":28,"short_name":"sunglasses","short_names":["sunglasses"],"text":null,"texts":["8)"],"category":"People","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMIRKING FACE","unified":"1F60F","variations":[],"docomo":"E72C","au":"EABF","softbank":"E402","google":"FE343","image":"1f60f.png","sheet_x":26,"sheet_y":29,"short_name":"smirk","short_names":["smirk"],"text":null,"texts":null,"category":"People","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NEUTRAL FACE","unified":"1F610","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f610.png","sheet_x":26,"sheet_y":30,"short_name":"neutral_face","short_names":["neutral_face"],"text":null,"texts":[":|",":-|"],"category":"People","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"EXPRESSIONLESS FACE","unified":"1F611","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f611.png","sheet_x":26,"sheet_y":31,"short_name":"expressionless","short_names":["expressionless"],"text":null,"texts":null,"category":"People","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UNAMUSED FACE","unified":"1F612","variations":[],"docomo":"E725","au":"EAC9","softbank":"E40E","google":"FE326","image":"1f612.png","sheet_x":26,"sheet_y":32,"short_name":"unamused","short_names":["unamused"],"text":":(","texts":null,"category":"People","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH COLD SWEAT","unified":"1F613","variations":[],"docomo":"E723","au":"E5C6","softbank":"E108","google":"FE344","image":"1f613.png","sheet_x":26,"sheet_y":33,"short_name":"sweat","short_names":["sweat"],"text":null,"texts":null,"category":"People","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PENSIVE FACE","unified":"1F614","variations":[],"docomo":"E720","au":"EAC0","softbank":"E403","google":"FE340","image":"1f614.png","sheet_x":26,"sheet_y":34,"short_name":"pensive","short_names":["pensive"],"text":null,"texts":null,"category":"People","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONFUSED FACE","unified":"1F615","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f615.png","sheet_x":26,"sheet_y":35,"short_name":"confused","short_names":["confused"],"text":null,"texts":[":\\",":-\\",":\/",":-\/"],"category":"People","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONFOUNDED FACE","unified":"1F616","variations":[],"docomo":"E6F3","au":"EAC3","softbank":"E407","google":"FE33F","image":"1f616.png","sheet_x":26,"sheet_y":36,"short_name":"confounded","short_names":["confounded"],"text":null,"texts":null,"category":"People","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISSING FACE","unified":"1F617","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f617.png","sheet_x":26,"sheet_y":37,"short_name":"kissing","short_names":["kissing"],"text":null,"texts":null,"category":"People","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE THROWING A KISS","unified":"1F618","variations":[],"docomo":"E726","au":"EACF","softbank":"E418","google":"FE32C","image":"1f618.png","sheet_x":26,"sheet_y":38,"short_name":"kissing_heart","short_names":["kissing_heart"],"text":null,"texts":null,"category":"People","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISSING FACE WITH SMILING EYES","unified":"1F619","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f619.png","sheet_x":26,"sheet_y":39,"short_name":"kissing_smiling_eyes","short_names":["kissing_smiling_eyes"],"text":null,"texts":null,"category":"People","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISSING FACE WITH CLOSED EYES","unified":"1F61A","variations":[],"docomo":"E726","au":"EACE","softbank":"E417","google":"FE32D","image":"1f61a.png","sheet_x":26,"sheet_y":40,"short_name":"kissing_closed_eyes","short_names":["kissing_closed_eyes"],"text":null,"texts":null,"category":"People","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH STUCK-OUT TONGUE","unified":"1F61B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f61b.png","sheet_x":27,"sheet_y":0,"short_name":"stuck_out_tongue","short_names":["stuck_out_tongue"],"text":":p","texts":[":p",":-p",":P",":-P",":b",":-b"],"category":"People","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH STUCK-OUT TONGUE AND WINKING EYE","unified":"1F61C","variations":[],"docomo":"E728","au":"E4E7","softbank":"E105","google":"FE329","image":"1f61c.png","sheet_x":27,"sheet_y":1,"short_name":"stuck_out_tongue_winking_eye","short_names":["stuck_out_tongue_winking_eye"],"text":";p","texts":[";p",";-p",";b",";-b",";P",";-P"],"category":"People","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES","unified":"1F61D","variations":[],"docomo":"E728","au":"E4E7","softbank":"E409","google":"FE32A","image":"1f61d.png","sheet_x":27,"sheet_y":2,"short_name":"stuck_out_tongue_closed_eyes","short_names":["stuck_out_tongue_closed_eyes"],"text":null,"texts":null,"category":"People","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DISAPPOINTED FACE","unified":"1F61E","variations":[],"docomo":"E6F2","au":"EAC0","softbank":"E058","google":"FE323","image":"1f61e.png","sheet_x":27,"sheet_y":3,"short_name":"disappointed","short_names":["disappointed"],"text":":(","texts":["):",":(",":-("],"category":"People","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WORRIED FACE","unified":"1F61F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f61f.png","sheet_x":27,"sheet_y":4,"short_name":"worried","short_names":["worried"],"text":null,"texts":null,"category":"People","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANGRY FACE","unified":"1F620","variations":[],"docomo":"E6F1","au":"E472","softbank":"E059","google":"FE320","image":"1f620.png","sheet_x":27,"sheet_y":5,"short_name":"angry","short_names":["angry"],"text":null,"texts":[">:(",">:-("],"category":"People","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POUTING FACE","unified":"1F621","variations":[],"docomo":"E724","au":"EB5D","softbank":"E416","google":"FE33D","image":"1f621.png","sheet_x":27,"sheet_y":6,"short_name":"rage","short_names":["rage"],"text":null,"texts":null,"category":"People","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CRYING FACE","unified":"1F622","variations":[],"docomo":"E72E","au":"EB69","softbank":"E413","google":"FE339","image":"1f622.png","sheet_x":27,"sheet_y":7,"short_name":"cry","short_names":["cry"],"text":":'(","texts":[":'("],"category":"People","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PERSEVERING FACE","unified":"1F623","variations":[],"docomo":"E72B","au":"EAC2","softbank":"E406","google":"FE33C","image":"1f623.png","sheet_x":27,"sheet_y":8,"short_name":"persevere","short_names":["persevere"],"text":null,"texts":null,"category":"People","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH LOOK OF TRIUMPH","unified":"1F624","variations":[],"docomo":"E753","au":"EAC1","softbank":"E404","google":"FE328","image":"1f624.png","sheet_x":27,"sheet_y":9,"short_name":"triumph","short_names":["triumph"],"text":null,"texts":null,"category":"People","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DISAPPOINTED BUT RELIEVED FACE","unified":"1F625","variations":[],"docomo":"E723","au":"E5C6","softbank":"E401","google":"FE345","image":"1f625.png","sheet_x":27,"sheet_y":10,"short_name":"disappointed_relieved","short_names":["disappointed_relieved"],"text":null,"texts":null,"category":"People","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FROWNING FACE WITH OPEN MOUTH","unified":"1F626","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f626.png","sheet_x":27,"sheet_y":11,"short_name":"frowning","short_names":["frowning"],"text":null,"texts":null,"category":"People","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ANGUISHED FACE","unified":"1F627","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f627.png","sheet_x":27,"sheet_y":12,"short_name":"anguished","short_names":["anguished"],"text":null,"texts":["D:"],"category":"People","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FEARFUL FACE","unified":"1F628","variations":[],"docomo":"E757","au":"EAC6","softbank":"E40B","google":"FE33B","image":"1f628.png","sheet_x":27,"sheet_y":13,"short_name":"fearful","short_names":["fearful"],"text":null,"texts":null,"category":"People","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WEARY FACE","unified":"1F629","variations":[],"docomo":"E6F3","au":"EB67","softbank":"E403","google":"FE321","image":"1f629.png","sheet_x":27,"sheet_y":14,"short_name":"weary","short_names":["weary"],"text":null,"texts":null,"category":"People","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLEEPY FACE","unified":"1F62A","variations":[],"docomo":"E701","au":"EAC4","softbank":"E408","google":"FE342","image":"1f62a.png","sheet_x":27,"sheet_y":15,"short_name":"sleepy","short_names":["sleepy"],"text":null,"texts":null,"category":"People","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TIRED FACE","unified":"1F62B","variations":[],"docomo":"E72B","au":"E474","softbank":"E406","google":"FE346","image":"1f62b.png","sheet_x":27,"sheet_y":16,"short_name":"tired_face","short_names":["tired_face"],"text":null,"texts":null,"category":"People","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRIMACING FACE","unified":"1F62C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f62c.png","sheet_x":27,"sheet_y":17,"short_name":"grimacing","short_names":["grimacing"],"text":null,"texts":null,"category":"People","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LOUDLY CRYING FACE","unified":"1F62D","variations":[],"docomo":"E72D","au":"E473","softbank":"E411","google":"FE33A","image":"1f62d.png","sheet_x":27,"sheet_y":18,"short_name":"sob","short_names":["sob"],"text":":'(","texts":null,"category":"People","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH OPEN MOUTH","unified":"1F62E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f62e.png","sheet_x":27,"sheet_y":19,"short_name":"open_mouth","short_names":["open_mouth"],"text":null,"texts":[":o",":-o"],"category":"People","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HUSHED FACE","unified":"1F62F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f62f.png","sheet_x":27,"sheet_y":20,"short_name":"hushed","short_names":["hushed"],"text":null,"texts":null,"category":"People","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH OPEN MOUTH AND COLD SWEAT","unified":"1F630","variations":[],"docomo":"E723","au":"EACB","softbank":"E40F","google":"FE325","image":"1f630.png","sheet_x":27,"sheet_y":21,"short_name":"cold_sweat","short_names":["cold_sweat"],"text":null,"texts":null,"category":"People","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE SCREAMING IN FEAR","unified":"1F631","variations":[],"docomo":"E757","au":"E5C5","softbank":"E107","google":"FE341","image":"1f631.png","sheet_x":27,"sheet_y":22,"short_name":"scream","short_names":["scream"],"text":null,"texts":null,"category":"People","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ASTONISHED FACE","unified":"1F632","variations":[],"docomo":"E6F4","au":"EACA","softbank":"E410","google":"FE322","image":"1f632.png","sheet_x":27,"sheet_y":23,"short_name":"astonished","short_names":["astonished"],"text":null,"texts":null,"category":"People","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FLUSHED FACE","unified":"1F633","variations":[],"docomo":"E72A","au":"EAC8","softbank":"E40D","google":"FE32F","image":"1f633.png","sheet_x":27,"sheet_y":24,"short_name":"flushed","short_names":["flushed"],"text":null,"texts":null,"category":"People","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLEEPING FACE","unified":"1F634","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f634.png","sheet_x":27,"sheet_y":25,"short_name":"sleeping","short_names":["sleeping"],"text":null,"texts":null,"category":"People","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DIZZY FACE","unified":"1F635","variations":[],"docomo":"E6F4","au":"E5AE","softbank":"E406","google":"FE324","image":"1f635.png","sheet_x":27,"sheet_y":26,"short_name":"dizzy_face","short_names":["dizzy_face"],"text":null,"texts":null,"category":"People","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITHOUT MOUTH","unified":"1F636","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f636.png","sheet_x":27,"sheet_y":27,"short_name":"no_mouth","short_names":["no_mouth"],"text":null,"texts":null,"category":"People","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH MEDICAL MASK","unified":"1F637","variations":[],"docomo":null,"au":"EAC7","softbank":"E40C","google":"FE32E","image":"1f637.png","sheet_x":27,"sheet_y":28,"short_name":"mask","short_names":["mask"],"text":null,"texts":null,"category":"People","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"GRINNING CAT FACE WITH SMILING EYES","unified":"1F638","variations":[],"docomo":"E753","au":"EB7F","softbank":"E404","google":"FE349","image":"1f638.png","sheet_x":27,"sheet_y":29,"short_name":"smile_cat","short_names":["smile_cat"],"text":null,"texts":null,"category":"People","sort_order":80,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAT FACE WITH TEARS OF JOY","unified":"1F639","variations":[],"docomo":"E72A","au":"EB63","softbank":"E412","google":"FE34A","image":"1f639.png","sheet_x":27,"sheet_y":30,"short_name":"joy_cat","short_names":["joy_cat"],"text":null,"texts":null,"category":"People","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING CAT FACE WITH OPEN MOUTH","unified":"1F63A","variations":[],"docomo":"E6F0","au":"EB61","softbank":"E057","google":"FE348","image":"1f63a.png","sheet_x":27,"sheet_y":31,"short_name":"smiley_cat","short_names":["smiley_cat"],"text":null,"texts":null,"category":"People","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMILING CAT FACE WITH HEART-SHAPED EYES","unified":"1F63B","variations":[],"docomo":"E726","au":"EB65","softbank":"E106","google":"FE34C","image":"1f63b.png","sheet_x":27,"sheet_y":32,"short_name":"heart_eyes_cat","short_names":["heart_eyes_cat"],"text":null,"texts":null,"category":"People","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CAT FACE WITH WRY SMILE","unified":"1F63C","variations":[],"docomo":"E753","au":"EB6A","softbank":"E404","google":"FE34F","image":"1f63c.png","sheet_x":27,"sheet_y":33,"short_name":"smirk_cat","short_names":["smirk_cat"],"text":null,"texts":null,"category":"People","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KISSING CAT FACE WITH CLOSED EYES","unified":"1F63D","variations":[],"docomo":"E726","au":"EB60","softbank":"E418","google":"FE34B","image":"1f63d.png","sheet_x":27,"sheet_y":34,"short_name":"kissing_cat","short_names":["kissing_cat"],"text":null,"texts":null,"category":"People","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POUTING CAT FACE","unified":"1F63E","variations":[],"docomo":"E724","au":"EB5E","softbank":"E416","google":"FE34E","image":"1f63e.png","sheet_x":27,"sheet_y":35,"short_name":"pouting_cat","short_names":["pouting_cat"],"text":null,"texts":null,"category":"People","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CRYING CAT FACE","unified":"1F63F","variations":[],"docomo":"E72E","au":"EB68","softbank":"E413","google":"FE34D","image":"1f63f.png","sheet_x":27,"sheet_y":36,"short_name":"crying_cat_face","short_names":["crying_cat_face"],"text":null,"texts":null,"category":"People","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WEARY CAT FACE","unified":"1F640","variations":[],"docomo":"E6F3","au":"EB66","softbank":"E403","google":"FE350","image":"1f640.png","sheet_x":27,"sheet_y":37,"short_name":"scream_cat","short_names":["scream_cat"],"text":null,"texts":null,"category":"People","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLIGHTLY FROWNING FACE","unified":"1F641","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f641.png","sheet_x":27,"sheet_y":38,"short_name":"slightly_frowning_face","short_names":["slightly_frowning_face"],"text":null,"texts":null,"category":"People","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLIGHTLY SMILING FACE","unified":"1F642","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f642.png","sheet_x":27,"sheet_y":39,"short_name":"slightly_smiling_face","short_names":["slightly_smiling_face"],"text":null,"texts":null,"category":"People","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UPSIDE-DOWN FACE","unified":"1F643","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f643.png","sheet_x":27,"sheet_y":40,"short_name":"upside_down_face","short_names":["upside_down_face"],"text":null,"texts":null,"category":"People","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH ROLLING EYES","unified":"1F644","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f644.png","sheet_x":28,"sheet_y":0,"short_name":"face_with_rolling_eyes","short_names":["face_with_rolling_eyes"],"text":null,"texts":null,"category":"People","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH NO GOOD GESTURE","unified":"1F645","variations":[],"docomo":"E72F","au":"EAD7","softbank":"E423","google":"FE351","image":"1f645.png","sheet_x":28,"sheet_y":1,"short_name":"no_good","short_names":["no_good"],"text":null,"texts":null,"category":"People","sort_order":148,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F645-1F3FB":{"unified":"1F645-1F3FB","image":"1f645-1f3fb.png","sheet_x":28,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F645-1F3FC":{"unified":"1F645-1F3FC","image":"1f645-1f3fc.png","sheet_x":28,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F645-1F3FD":{"unified":"1F645-1F3FD","image":"1f645-1f3fd.png","sheet_x":28,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F645-1F3FE":{"unified":"1F645-1F3FE","image":"1f645-1f3fe.png","sheet_x":28,"sheet_y":5,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F645-1F3FF":{"unified":"1F645-1F3FF","image":"1f645-1f3ff.png","sheet_x":28,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"FACE WITH OK GESTURE","unified":"1F646","variations":[],"docomo":"E70B","au":"EAD8","softbank":"E424","google":"FE352","image":"1f646.png","sheet_x":28,"sheet_y":7,"short_name":"ok_woman","short_names":["ok_woman"],"text":null,"texts":null,"category":"People","sort_order":149,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F646-1F3FB":{"unified":"1F646-1F3FB","image":"1f646-1f3fb.png","sheet_x":28,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F646-1F3FC":{"unified":"1F646-1F3FC","image":"1f646-1f3fc.png","sheet_x":28,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F646-1F3FD":{"unified":"1F646-1F3FD","image":"1f646-1f3fd.png","sheet_x":28,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F646-1F3FE":{"unified":"1F646-1F3FE","image":"1f646-1f3fe.png","sheet_x":28,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F646-1F3FF":{"unified":"1F646-1F3FF","image":"1f646-1f3ff.png","sheet_x":28,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON BOWING DEEPLY","unified":"1F647","variations":[],"docomo":null,"au":"EAD9","softbank":"E426","google":"FE353","image":"1f647.png","sheet_x":28,"sheet_y":13,"short_name":"bow","short_names":["bow"],"text":null,"texts":null,"category":"People","sort_order":146,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F647-1F3FB":{"unified":"1F647-1F3FB","image":"1f647-1f3fb.png","sheet_x":28,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F647-1F3FC":{"unified":"1F647-1F3FC","image":"1f647-1f3fc.png","sheet_x":28,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F647-1F3FD":{"unified":"1F647-1F3FD","image":"1f647-1f3fd.png","sheet_x":28,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F647-1F3FE":{"unified":"1F647-1F3FE","image":"1f647-1f3fe.png","sheet_x":28,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F647-1F3FF":{"unified":"1F647-1F3FF","image":"1f647-1f3ff.png","sheet_x":28,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"SEE-NO-EVIL MONKEY","unified":"1F648","variations":[],"docomo":null,"au":"EB50","softbank":null,"google":"FE354","image":"1f648.png","sheet_x":28,"sheet_y":19,"short_name":"see_no_evil","short_names":["see_no_evil"],"text":null,"texts":null,"category":"Nature","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HEAR-NO-EVIL MONKEY","unified":"1F649","variations":[],"docomo":null,"au":"EB52","softbank":null,"google":"FE356","image":"1f649.png","sheet_x":28,"sheet_y":20,"short_name":"hear_no_evil","short_names":["hear_no_evil"],"text":null,"texts":null,"category":"Nature","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SPEAK-NO-EVIL MONKEY","unified":"1F64A","variations":[],"docomo":null,"au":"EB51","softbank":null,"google":"FE355","image":"1f64a.png","sheet_x":28,"sheet_y":21,"short_name":"speak_no_evil","short_names":["speak_no_evil"],"text":null,"texts":null,"category":"Nature","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAPPY PERSON RAISING ONE HAND","unified":"1F64B","variations":[],"docomo":null,"au":"EB85","softbank":"E012","google":"FE357","image":"1f64b.png","sheet_x":28,"sheet_y":22,"short_name":"raising_hand","short_names":["raising_hand"],"text":null,"texts":null,"category":"People","sort_order":150,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F64B-1F3FB":{"unified":"1F64B-1F3FB","image":"1f64b-1f3fb.png","sheet_x":28,"sheet_y":23,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64B-1F3FC":{"unified":"1F64B-1F3FC","image":"1f64b-1f3fc.png","sheet_x":28,"sheet_y":24,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64B-1F3FD":{"unified":"1F64B-1F3FD","image":"1f64b-1f3fd.png","sheet_x":28,"sheet_y":25,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64B-1F3FE":{"unified":"1F64B-1F3FE","image":"1f64b-1f3fe.png","sheet_x":28,"sheet_y":26,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64B-1F3FF":{"unified":"1F64B-1F3FF","image":"1f64b-1f3ff.png","sheet_x":28,"sheet_y":27,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON RAISING BOTH HANDS IN CELEBRATION","unified":"1F64C","variations":[],"docomo":null,"au":"EB86","softbank":"E427","google":"FE358","image":"1f64c.png","sheet_x":28,"sheet_y":28,"short_name":"raised_hands","short_names":["raised_hands"],"text":null,"texts":null,"category":"People","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F64C-1F3FB":{"unified":"1F64C-1F3FB","image":"1f64c-1f3fb.png","sheet_x":28,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64C-1F3FC":{"unified":"1F64C-1F3FC","image":"1f64c-1f3fc.png","sheet_x":28,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64C-1F3FD":{"unified":"1F64C-1F3FD","image":"1f64c-1f3fd.png","sheet_x":28,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64C-1F3FE":{"unified":"1F64C-1F3FE","image":"1f64c-1f3fe.png","sheet_x":28,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64C-1F3FF":{"unified":"1F64C-1F3FF","image":"1f64c-1f3ff.png","sheet_x":28,"sheet_y":33,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON FROWNING","unified":"1F64D","variations":[],"docomo":"E6F3","au":"EB87","softbank":"E403","google":"FE359","image":"1f64d.png","sheet_x":28,"sheet_y":34,"short_name":"person_frowning","short_names":["person_frowning"],"text":null,"texts":null,"category":"People","sort_order":152,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F64D-1F3FB":{"unified":"1F64D-1F3FB","image":"1f64d-1f3fb.png","sheet_x":28,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64D-1F3FC":{"unified":"1F64D-1F3FC","image":"1f64d-1f3fc.png","sheet_x":28,"sheet_y":36,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64D-1F3FD":{"unified":"1F64D-1F3FD","image":"1f64d-1f3fd.png","sheet_x":28,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64D-1F3FE":{"unified":"1F64D-1F3FE","image":"1f64d-1f3fe.png","sheet_x":28,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64D-1F3FF":{"unified":"1F64D-1F3FF","image":"1f64d-1f3ff.png","sheet_x":28,"sheet_y":39,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON WITH POUTING FACE","unified":"1F64E","variations":[],"docomo":"E6F1","au":"EB88","softbank":"E416","google":"FE35A","image":"1f64e.png","sheet_x":28,"sheet_y":40,"short_name":"person_with_pouting_face","short_names":["person_with_pouting_face"],"text":null,"texts":null,"category":"People","sort_order":151,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F64E-1F3FB":{"unified":"1F64E-1F3FB","image":"1f64e-1f3fb.png","sheet_x":29,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64E-1F3FC":{"unified":"1F64E-1F3FC","image":"1f64e-1f3fc.png","sheet_x":29,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64E-1F3FD":{"unified":"1F64E-1F3FD","image":"1f64e-1f3fd.png","sheet_x":29,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64E-1F3FE":{"unified":"1F64E-1F3FE","image":"1f64e-1f3fe.png","sheet_x":29,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64E-1F3FF":{"unified":"1F64E-1F3FF","image":"1f64e-1f3ff.png","sheet_x":29,"sheet_y":4,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PERSON WITH FOLDED HANDS","unified":"1F64F","variations":[],"docomo":null,"au":"EAD2","softbank":"E41D","google":"FE35B","image":"1f64f.png","sheet_x":29,"sheet_y":5,"short_name":"pray","short_names":["pray"],"text":null,"texts":null,"category":"People","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F64F-1F3FB":{"unified":"1F64F-1F3FB","image":"1f64f-1f3fb.png","sheet_x":29,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64F-1F3FC":{"unified":"1F64F-1F3FC","image":"1f64f-1f3fc.png","sheet_x":29,"sheet_y":7,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64F-1F3FD":{"unified":"1F64F-1F3FD","image":"1f64f-1f3fd.png","sheet_x":29,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64F-1F3FE":{"unified":"1F64F-1F3FE","image":"1f64f-1f3fe.png","sheet_x":29,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F64F-1F3FF":{"unified":"1F64F-1F3FF","image":"1f64f-1f3ff.png","sheet_x":29,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"ROCKET","unified":"1F680","variations":[],"docomo":null,"au":"E5C8","softbank":"E10D","google":"FE7ED","image":"1f680.png","sheet_x":29,"sheet_y":11,"short_name":"rocket","short_names":["rocket"],"text":null,"texts":null,"category":"Places","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HELICOPTER","unified":"1F681","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f681.png","sheet_x":29,"sheet_y":12,"short_name":"helicopter","short_names":["helicopter"],"text":null,"texts":null,"category":"Places","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STEAM LOCOMOTIVE","unified":"1F682","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f682.png","sheet_x":29,"sheet_y":13,"short_name":"steam_locomotive","short_names":["steam_locomotive"],"text":null,"texts":null,"category":"Places","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAILWAY CAR","unified":"1F683","variations":[],"docomo":"E65B","au":"E4B5","softbank":"E01E","google":"FE7DF","image":"1f683.png","sheet_x":29,"sheet_y":14,"short_name":"railway_car","short_names":["railway_car"],"text":null,"texts":null,"category":"Places","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIGH-SPEED TRAIN","unified":"1F684","variations":[],"docomo":"E65D","au":"E4B0","softbank":"E435","google":"FE7E2","image":"1f684.png","sheet_x":29,"sheet_y":15,"short_name":"bullettrain_side","short_names":["bullettrain_side"],"text":null,"texts":null,"category":"Places","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HIGH-SPEED TRAIN WITH BULLET NOSE","unified":"1F685","variations":[],"docomo":"E65D","au":"E4B0","softbank":"E01F","google":"FE7E3","image":"1f685.png","sheet_x":29,"sheet_y":16,"short_name":"bullettrain_front","short_names":["bullettrain_front"],"text":null,"texts":null,"category":"Places","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRAIN","unified":"1F686","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f686.png","sheet_x":29,"sheet_y":17,"short_name":"train2","short_names":["train2"],"text":null,"texts":null,"category":"Places","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"METRO","unified":"1F687","variations":[],"docomo":"E65C","au":"E5BC","softbank":"E434","google":"FE7E0","image":"1f687.png","sheet_x":29,"sheet_y":18,"short_name":"metro","short_names":["metro"],"text":null,"texts":null,"category":"Places","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LIGHT RAIL","unified":"1F688","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f688.png","sheet_x":29,"sheet_y":19,"short_name":"light_rail","short_names":["light_rail"],"text":null,"texts":null,"category":"Places","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"STATION","unified":"1F689","variations":[],"docomo":null,"au":"EB6D","softbank":"E039","google":"FE7EC","image":"1f689.png","sheet_x":29,"sheet_y":20,"short_name":"station","short_names":["station"],"text":null,"texts":null,"category":"Places","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRAM","unified":"1F68A","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f68a.png","sheet_x":29,"sheet_y":21,"short_name":"tram","short_names":["tram"],"text":null,"texts":null,"category":"Places","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRAM CAR","unified":"1F68B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f68b.png","sheet_x":29,"sheet_y":22,"short_name":"train","short_names":["train"],"text":null,"texts":null,"category":"Places","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUS","unified":"1F68C","variations":[],"docomo":"E660","au":"E4AF","softbank":"E159","google":"FE7E6","image":"1f68c.png","sheet_x":29,"sheet_y":23,"short_name":"bus","short_names":["bus"],"text":null,"texts":null,"category":"Places","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ONCOMING BUS","unified":"1F68D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f68d.png","sheet_x":29,"sheet_y":24,"short_name":"oncoming_bus","short_names":["oncoming_bus"],"text":null,"texts":null,"category":"Places","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TROLLEYBUS","unified":"1F68E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f68e.png","sheet_x":29,"sheet_y":25,"short_name":"trolleybus","short_names":["trolleybus"],"text":null,"texts":null,"category":"Places","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BUS STOP","unified":"1F68F","variations":[],"docomo":null,"au":"E4A7","softbank":"E150","google":"FE7E7","image":"1f68f.png","sheet_x":29,"sheet_y":26,"short_name":"busstop","short_names":["busstop"],"text":null,"texts":null,"category":"Places","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MINIBUS","unified":"1F690","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f690.png","sheet_x":29,"sheet_y":27,"short_name":"minibus","short_names":["minibus"],"text":null,"texts":null,"category":"Places","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AMBULANCE","unified":"1F691","variations":[],"docomo":null,"au":"EAE0","softbank":"E431","google":"FE7F3","image":"1f691.png","sheet_x":29,"sheet_y":28,"short_name":"ambulance","short_names":["ambulance"],"text":null,"texts":null,"category":"Places","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FIRE ENGINE","unified":"1F692","variations":[],"docomo":null,"au":"EADF","softbank":"E430","google":"FE7F2","image":"1f692.png","sheet_x":29,"sheet_y":29,"short_name":"fire_engine","short_names":["fire_engine"],"text":null,"texts":null,"category":"Places","sort_order":9,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POLICE CAR","unified":"1F693","variations":[],"docomo":null,"au":"EAE1","softbank":"E432","google":"FE7F4","image":"1f693.png","sheet_x":29,"sheet_y":30,"short_name":"police_car","short_names":["police_car"],"text":null,"texts":null,"category":"Places","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ONCOMING POLICE CAR","unified":"1F694","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f694.png","sheet_x":29,"sheet_y":31,"short_name":"oncoming_police_car","short_names":["oncoming_police_car"],"text":null,"texts":null,"category":"Places","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TAXI","unified":"1F695","variations":[],"docomo":"E65E","au":"E4B1","softbank":"E15A","google":"FE7EF","image":"1f695.png","sheet_x":29,"sheet_y":32,"short_name":"taxi","short_names":["taxi"],"text":null,"texts":null,"category":"Places","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ONCOMING TAXI","unified":"1F696","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f696.png","sheet_x":29,"sheet_y":33,"short_name":"oncoming_taxi","short_names":["oncoming_taxi"],"text":null,"texts":null,"category":"Places","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AUTOMOBILE","unified":"1F697","variations":[],"docomo":"E65E","au":"E4B1","softbank":"E01B","google":"FE7E4","image":"1f697.png","sheet_x":29,"sheet_y":34,"short_name":"car","short_names":["car","red_car"],"text":null,"texts":null,"category":"Places","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ONCOMING AUTOMOBILE","unified":"1F698","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f698.png","sheet_x":29,"sheet_y":35,"short_name":"oncoming_automobile","short_names":["oncoming_automobile"],"text":null,"texts":null,"category":"Places","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RECREATIONAL VEHICLE","unified":"1F699","variations":[],"docomo":"E65F","au":"E4B1","softbank":"E42E","google":"FE7E5","image":"1f699.png","sheet_x":29,"sheet_y":36,"short_name":"blue_car","short_names":["blue_car"],"text":null,"texts":null,"category":"Places","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DELIVERY TRUCK","unified":"1F69A","variations":[],"docomo":null,"au":"E4B2","softbank":"E42F","google":"FE7F1","image":"1f69a.png","sheet_x":29,"sheet_y":37,"short_name":"truck","short_names":["truck"],"text":null,"texts":null,"category":"Places","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ARTICULATED LORRY","unified":"1F69B","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f69b.png","sheet_x":29,"sheet_y":38,"short_name":"articulated_lorry","short_names":["articulated_lorry"],"text":null,"texts":null,"category":"Places","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRACTOR","unified":"1F69C","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f69c.png","sheet_x":29,"sheet_y":39,"short_name":"tractor","short_names":["tractor"],"text":null,"texts":null,"category":"Places","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONORAIL","unified":"1F69D","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f69d.png","sheet_x":29,"sheet_y":40,"short_name":"monorail","short_names":["monorail"],"text":null,"texts":null,"category":"Places","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUNTAIN RAILWAY","unified":"1F69E","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f69e.png","sheet_x":30,"sheet_y":0,"short_name":"mountain_railway","short_names":["mountain_railway"],"text":null,"texts":null,"category":"Places","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SUSPENSION RAILWAY","unified":"1F69F","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f69f.png","sheet_x":30,"sheet_y":1,"short_name":"suspension_railway","short_names":["suspension_railway"],"text":null,"texts":null,"category":"Places","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOUNTAIN CABLEWAY","unified":"1F6A0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6a0.png","sheet_x":30,"sheet_y":2,"short_name":"mountain_cableway","short_names":["mountain_cableway"],"text":null,"texts":null,"category":"Places","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AERIAL TRAMWAY","unified":"1F6A1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6a1.png","sheet_x":30,"sheet_y":3,"short_name":"aerial_tramway","short_names":["aerial_tramway"],"text":null,"texts":null,"category":"Places","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHIP","unified":"1F6A2","variations":[],"docomo":"E661","au":"EA82","softbank":"E202","google":"FE7E8","image":"1f6a2.png","sheet_x":30,"sheet_y":4,"short_name":"ship","short_names":["ship"],"text":null,"texts":null,"category":"Places","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROWBOAT","unified":"1F6A3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6a3.png","sheet_x":30,"sheet_y":5,"short_name":"rowboat","short_names":["rowboat"],"text":null,"texts":null,"category":"Activity","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F6A3-1F3FB":{"unified":"1F6A3-1F3FB","image":"1f6a3-1f3fb.png","sheet_x":30,"sheet_y":6,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6A3-1F3FC":{"unified":"1F6A3-1F3FC","image":"1f6a3-1f3fc.png","sheet_x":30,"sheet_y":7,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6A3-1F3FD":{"unified":"1F6A3-1F3FD","image":"1f6a3-1f3fd.png","sheet_x":30,"sheet_y":8,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6A3-1F3FE":{"unified":"1F6A3-1F3FE","image":"1f6a3-1f3fe.png","sheet_x":30,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6A3-1F3FF":{"unified":"1F6A3-1F3FF","image":"1f6a3-1f3ff.png","sheet_x":30,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"SPEEDBOAT","unified":"1F6A4","variations":[],"docomo":"E6A3","au":"E4B4","softbank":"E135","google":"FE7EE","image":"1f6a4.png","sheet_x":30,"sheet_y":11,"short_name":"speedboat","short_names":["speedboat"],"text":null,"texts":null,"category":"Places","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HORIZONTAL TRAFFIC LIGHT","unified":"1F6A5","variations":[],"docomo":"E66D","au":"E46A","softbank":"E14E","google":"FE7F7","image":"1f6a5.png","sheet_x":30,"sheet_y":12,"short_name":"traffic_light","short_names":["traffic_light"],"text":null,"texts":null,"category":"Places","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"VERTICAL TRAFFIC LIGHT","unified":"1F6A6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6a6.png","sheet_x":30,"sheet_y":13,"short_name":"vertical_traffic_light","short_names":["vertical_traffic_light"],"text":null,"texts":null,"category":"Places","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CONSTRUCTION SIGN","unified":"1F6A7","variations":[],"docomo":null,"au":"E5D7","softbank":"E137","google":"FE7F8","image":"1f6a7.png","sheet_x":30,"sheet_y":14,"short_name":"construction","short_names":["construction"],"text":null,"texts":null,"category":"Places","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POLICE CARS REVOLVING LIGHT","unified":"1F6A8","variations":[],"docomo":null,"au":"EB73","softbank":"E432","google":"FE7F9","image":"1f6a8.png","sheet_x":30,"sheet_y":15,"short_name":"rotating_light","short_names":["rotating_light"],"text":null,"texts":null,"category":"Places","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TRIANGULAR FLAG ON POST","unified":"1F6A9","variations":[],"docomo":"E6DE","au":"EB2C","softbank":null,"google":"FEB22","image":"1f6a9.png","sheet_x":30,"sheet_y":16,"short_name":"triangular_flag_on_post","short_names":["triangular_flag_on_post"],"text":null,"texts":null,"category":"Objects","sort_order":163,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DOOR","unified":"1F6AA","variations":[],"docomo":"E714","au":null,"softbank":null,"google":"FE4F3","image":"1f6aa.png","sheet_x":30,"sheet_y":17,"short_name":"door","short_names":["door"],"text":null,"texts":null,"category":"Objects","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO ENTRY SIGN","unified":"1F6AB","variations":[],"docomo":"E738","au":"E541","softbank":null,"google":"FEB48","image":"1f6ab.png","sheet_x":30,"sheet_y":18,"short_name":"no_entry_sign","short_names":["no_entry_sign"],"text":null,"texts":null,"category":"Symbols","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMOKING SYMBOL","unified":"1F6AC","variations":[],"docomo":"E67F","au":"E47D","softbank":"E30E","google":"FEB1E","image":"1f6ac.png","sheet_x":30,"sheet_y":19,"short_name":"smoking","short_names":["smoking"],"text":null,"texts":null,"category":"Objects","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO SMOKING SYMBOL","unified":"1F6AD","variations":[],"docomo":"E680","au":"E47E","softbank":"E208","google":"FEB1F","image":"1f6ad.png","sheet_x":30,"sheet_y":20,"short_name":"no_smoking","short_names":["no_smoking"],"text":null,"texts":null,"category":"Symbols","sort_order":116,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PUT LITTER IN ITS PLACE SYMBOL","unified":"1F6AE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6ae.png","sheet_x":30,"sheet_y":21,"short_name":"put_litter_in_its_place","short_names":["put_litter_in_its_place"],"text":null,"texts":null,"category":"Symbols","sort_order":124,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"DO NOT LITTER SYMBOL","unified":"1F6AF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6af.png","sheet_x":30,"sheet_y":22,"short_name":"do_not_litter","short_names":["do_not_litter"],"text":null,"texts":null,"category":"Symbols","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"POTABLE WATER SYMBOL","unified":"1F6B0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b0.png","sheet_x":30,"sheet_y":23,"short_name":"potable_water","short_names":["potable_water"],"text":null,"texts":null,"category":"Symbols","sort_order":119,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NON-POTABLE WATER SYMBOL","unified":"1F6B1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b1.png","sheet_x":30,"sheet_y":24,"short_name":"non-potable_water","short_names":["non-potable_water"],"text":null,"texts":null,"category":"Symbols","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BICYCLE","unified":"1F6B2","variations":[],"docomo":"E71D","au":"E4AE","softbank":"E136","google":"FE7EB","image":"1f6b2.png","sheet_x":30,"sheet_y":25,"short_name":"bike","short_names":["bike"],"text":null,"texts":null,"category":"Places","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NO BICYCLES","unified":"1F6B3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b3.png","sheet_x":30,"sheet_y":26,"short_name":"no_bicycles","short_names":["no_bicycles"],"text":null,"texts":null,"category":"Symbols","sort_order":78,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BICYCLIST","unified":"1F6B4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b4.png","sheet_x":30,"sheet_y":27,"short_name":"bicyclist","short_names":["bicyclist"],"text":null,"texts":null,"category":"Activity","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F6B4-1F3FB":{"unified":"1F6B4-1F3FB","image":"1f6b4-1f3fb.png","sheet_x":30,"sheet_y":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B4-1F3FC":{"unified":"1F6B4-1F3FC","image":"1f6b4-1f3fc.png","sheet_x":30,"sheet_y":29,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B4-1F3FD":{"unified":"1F6B4-1F3FD","image":"1f6b4-1f3fd.png","sheet_x":30,"sheet_y":30,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B4-1F3FE":{"unified":"1F6B4-1F3FE","image":"1f6b4-1f3fe.png","sheet_x":30,"sheet_y":31,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B4-1F3FF":{"unified":"1F6B4-1F3FF","image":"1f6b4-1f3ff.png","sheet_x":30,"sheet_y":32,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"MOUNTAIN BICYCLIST","unified":"1F6B5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b5.png","sheet_x":30,"sheet_y":33,"short_name":"mountain_bicyclist","short_names":["mountain_bicyclist"],"text":null,"texts":null,"category":"Activity","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F6B5-1F3FB":{"unified":"1F6B5-1F3FB","image":"1f6b5-1f3fb.png","sheet_x":30,"sheet_y":34,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B5-1F3FC":{"unified":"1F6B5-1F3FC","image":"1f6b5-1f3fc.png","sheet_x":30,"sheet_y":35,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B5-1F3FD":{"unified":"1F6B5-1F3FD","image":"1f6b5-1f3fd.png","sheet_x":30,"sheet_y":36,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B5-1F3FE":{"unified":"1F6B5-1F3FE","image":"1f6b5-1f3fe.png","sheet_x":30,"sheet_y":37,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B5-1F3FF":{"unified":"1F6B5-1F3FF","image":"1f6b5-1f3ff.png","sheet_x":30,"sheet_y":38,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"PEDESTRIAN","unified":"1F6B6","variations":[],"docomo":"E733","au":"EB72","softbank":"E201","google":"FE7F0","image":"1f6b6.png","sheet_x":30,"sheet_y":39,"short_name":"walking","short_names":["walking"],"text":null,"texts":null,"category":"People","sort_order":139,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F6B6-1F3FB":{"unified":"1F6B6-1F3FB","image":"1f6b6-1f3fb.png","sheet_x":30,"sheet_y":40,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B6-1F3FC":{"unified":"1F6B6-1F3FC","image":"1f6b6-1f3fc.png","sheet_x":31,"sheet_y":0,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B6-1F3FD":{"unified":"1F6B6-1F3FD","image":"1f6b6-1f3fd.png","sheet_x":31,"sheet_y":1,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B6-1F3FE":{"unified":"1F6B6-1F3FE","image":"1f6b6-1f3fe.png","sheet_x":31,"sheet_y":2,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6B6-1F3FF":{"unified":"1F6B6-1F3FF","image":"1f6b6-1f3ff.png","sheet_x":31,"sheet_y":3,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"NO PEDESTRIANS","unified":"1F6B7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b7.png","sheet_x":31,"sheet_y":4,"short_name":"no_pedestrians","short_names":["no_pedestrians"],"text":null,"texts":null,"category":"Symbols","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHILDREN CROSSING","unified":"1F6B8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6b8.png","sheet_x":31,"sheet_y":5,"short_name":"children_crossing","short_names":["children_crossing"],"text":null,"texts":null,"category":"Symbols","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MENS SYMBOL","unified":"1F6B9","variations":[],"docomo":null,"au":null,"softbank":"E138","google":"FEB33","image":"1f6b9.png","sheet_x":31,"sheet_y":6,"short_name":"mens","short_names":["mens"],"text":null,"texts":null,"category":"Symbols","sort_order":120,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WOMENS SYMBOL","unified":"1F6BA","variations":[],"docomo":null,"au":null,"softbank":"E139","google":"FEB34","image":"1f6ba.png","sheet_x":31,"sheet_y":7,"short_name":"womens","short_names":["womens"],"text":null,"texts":null,"category":"Symbols","sort_order":121,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RESTROOM","unified":"1F6BB","variations":[],"docomo":"E66E","au":"E4A5","softbank":"E151","google":"FE506","image":"1f6bb.png","sheet_x":31,"sheet_y":8,"short_name":"restroom","short_names":["restroom"],"text":null,"texts":null,"category":"Symbols","sort_order":123,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BABY SYMBOL","unified":"1F6BC","variations":[],"docomo":null,"au":"EB18","softbank":"E13A","google":"FEB35","image":"1f6bc.png","sheet_x":31,"sheet_y":9,"short_name":"baby_symbol","short_names":["baby_symbol"],"text":null,"texts":null,"category":"Symbols","sort_order":122,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TOILET","unified":"1F6BD","variations":[],"docomo":"E66E","au":"E4A5","softbank":"E140","google":"FE507","image":"1f6bd.png","sheet_x":31,"sheet_y":10,"short_name":"toilet","short_names":["toilet"],"text":null,"texts":null,"category":"Objects","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"WATER CLOSET","unified":"1F6BE","variations":[],"docomo":"E66E","au":"E4A5","softbank":"E309","google":"FE508","image":"1f6be.png","sheet_x":31,"sheet_y":11,"short_name":"wc","short_names":["wc"],"text":null,"texts":null,"category":"Symbols","sort_order":117,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHOWER","unified":"1F6BF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6bf.png","sheet_x":31,"sheet_y":12,"short_name":"shower","short_names":["shower"],"text":null,"texts":null,"category":"Objects","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BATH","unified":"1F6C0","variations":[],"docomo":"E6F7","au":"E5D8","softbank":"E13F","google":"FE505","image":"1f6c0.png","sheet_x":31,"sheet_y":13,"short_name":"bath","short_names":["bath"],"text":null,"texts":null,"category":"Activity","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F6C0-1F3FB":{"unified":"1F6C0-1F3FB","image":"1f6c0-1f3fb.png","sheet_x":31,"sheet_y":14,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6C0-1F3FC":{"unified":"1F6C0-1F3FC","image":"1f6c0-1f3fc.png","sheet_x":31,"sheet_y":15,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6C0-1F3FD":{"unified":"1F6C0-1F3FD","image":"1f6c0-1f3fd.png","sheet_x":31,"sheet_y":16,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6C0-1F3FE":{"unified":"1F6C0-1F3FE","image":"1f6c0-1f3fe.png","sheet_x":31,"sheet_y":17,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F6C0-1F3FF":{"unified":"1F6C0-1F3FF","image":"1f6c0-1f3ff.png","sheet_x":31,"sheet_y":18,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"BATHTUB","unified":"1F6C1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6c1.png","sheet_x":31,"sheet_y":19,"short_name":"bathtub","short_names":["bathtub"],"text":null,"texts":null,"category":"Objects","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PASSPORT CONTROL","unified":"1F6C2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6c2.png","sheet_x":31,"sheet_y":20,"short_name":"passport_control","short_names":["passport_control"],"text":null,"texts":null,"category":"Symbols","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CUSTOMS","unified":"1F6C3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6c3.png","sheet_x":31,"sheet_y":21,"short_name":"customs","short_names":["customs"],"text":null,"texts":null,"category":"Symbols","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BAGGAGE CLAIM","unified":"1F6C4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6c4.png","sheet_x":31,"sheet_y":22,"short_name":"baggage_claim","short_names":["baggage_claim"],"text":null,"texts":null,"category":"Symbols","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LEFT LUGGAGE","unified":"1F6C5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6c5.png","sheet_x":31,"sheet_y":23,"short_name":"left_luggage","short_names":["left_luggage"],"text":null,"texts":null,"category":"Symbols","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"COUCH AND LAMP","unified":"1F6CB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6cb.png","sheet_x":31,"sheet_y":24,"short_name":"couch_and_lamp","short_names":["couch_and_lamp"],"text":null,"texts":null,"category":"Objects","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SLEEPING ACCOMMODATION","unified":"1F6CC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6cc.png","sheet_x":31,"sheet_y":25,"short_name":"sleeping_accommodation","short_names":["sleeping_accommodation"],"text":null,"texts":null,"category":"Objects","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHOPPING BAGS","unified":"1F6CD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6cd.png","sheet_x":31,"sheet_y":26,"short_name":"shopping_bags","short_names":["shopping_bags"],"text":null,"texts":null,"category":"Objects","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BELLHOP BELL","unified":"1F6CE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6ce.png","sheet_x":31,"sheet_y":27,"short_name":"bellhop_bell","short_names":["bellhop_bell"],"text":null,"texts":null,"category":"Objects","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"BED","unified":"1F6CF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6cf.png","sheet_x":31,"sheet_y":28,"short_name":"bed","short_names":["bed"],"text":null,"texts":null,"category":"Objects","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PLACE OF WORSHIP","unified":"1F6D0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6d0.png","sheet_x":31,"sheet_y":29,"short_name":"place_of_worship","short_names":["place_of_worship"],"text":null,"texts":null,"category":"Symbols","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HAMMER AND WRENCH","unified":"1F6E0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e0.png","sheet_x":31,"sheet_y":30,"short_name":"hammer_and_wrench","short_names":["hammer_and_wrench"],"text":null,"texts":null,"category":"Objects","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SHIELD","unified":"1F6E1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e1.png","sheet_x":31,"sheet_y":31,"short_name":"shield","short_names":["shield"],"text":null,"texts":null,"category":"Objects","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"OIL DRUM","unified":"1F6E2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e2.png","sheet_x":31,"sheet_y":32,"short_name":"oil_drum","short_names":["oil_drum"],"text":null,"texts":null,"category":"Objects","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOTORWAY","unified":"1F6E3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e3.png","sheet_x":31,"sheet_y":33,"short_name":"motorway","short_names":["motorway"],"text":null,"texts":null,"category":"Places","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"RAILWAY TRACK","unified":"1F6E4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e4.png","sheet_x":31,"sheet_y":34,"short_name":"railway_track","short_names":["railway_track"],"text":null,"texts":null,"category":"Places","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MOTOR BOAT","unified":"1F6E5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e5.png","sheet_x":31,"sheet_y":35,"short_name":"motor_boat","short_names":["motor_boat"],"text":null,"texts":null,"category":"Places","sort_order":42,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SMALL AIRPLANE","unified":"1F6E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6e9.png","sheet_x":31,"sheet_y":36,"short_name":"small_airplane","short_names":["small_airplane"],"text":null,"texts":null,"category":"Places","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AIRPLANE DEPARTURE","unified":"1F6EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6eb.png","sheet_x":31,"sheet_y":37,"short_name":"airplane_departure","short_names":["airplane_departure"],"text":null,"texts":null,"category":"Places","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"AIRPLANE ARRIVING","unified":"1F6EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6ec.png","sheet_x":31,"sheet_y":38,"short_name":"airplane_arriving","short_names":["airplane_arriving"],"text":null,"texts":null,"category":"Places","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SATELLITE","unified":"1F6F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6f0.png","sheet_x":31,"sheet_y":39,"short_name":"satellite","short_names":["satellite"],"text":null,"texts":null,"category":"Places","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"PASSENGER SHIP","unified":"1F6F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f6f3.png","sheet_x":31,"sheet_y":40,"short_name":"passenger_ship","short_names":["passenger_ship"],"text":null,"texts":null,"category":"Places","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ZIPPER-MOUTH FACE","unified":"1F910","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f910.png","sheet_x":32,"sheet_y":0,"short_name":"zipper_mouth_face","short_names":["zipper_mouth_face"],"text":null,"texts":null,"category":"People","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"MONEY-MOUTH FACE","unified":"1F911","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f911.png","sheet_x":32,"sheet_y":1,"short_name":"money_mouth_face","short_names":["money_mouth_face"],"text":null,"texts":null,"category":"People","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH THERMOMETER","unified":"1F912","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f912.png","sheet_x":32,"sheet_y":2,"short_name":"face_with_thermometer","short_names":["face_with_thermometer"],"text":null,"texts":null,"category":"People","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"NERD FACE","unified":"1F913","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f913.png","sheet_x":32,"sheet_y":3,"short_name":"nerd_face","short_names":["nerd_face"],"text":null,"texts":null,"category":"People","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"THINKING FACE","unified":"1F914","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f914.png","sheet_x":32,"sheet_y":4,"short_name":"thinking_face","short_names":["thinking_face"],"text":null,"texts":null,"category":"People","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"FACE WITH HEAD-BANDAGE","unified":"1F915","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f915.png","sheet_x":32,"sheet_y":5,"short_name":"face_with_head_bandage","short_names":["face_with_head_bandage"],"text":null,"texts":null,"category":"People","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"ROBOT FACE","unified":"1F916","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f916.png","sheet_x":32,"sheet_y":6,"short_name":"robot_face","short_names":["robot_face"],"text":null,"texts":null,"category":"People","sort_order":78,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HUGGING FACE","unified":"1F917","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f917.png","sheet_x":32,"sheet_y":7,"short_name":"hugging_face","short_names":["hugging_face"],"text":null,"texts":null,"category":"People","sort_order":28,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SIGN OF THE HORNS","unified":"1F918","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f918.png","sheet_x":32,"sheet_y":8,"short_name":"the_horns","short_names":["the_horns","sign_of_the_horns"],"text":null,"texts":null,"category":"People","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"skin_variations":{"1F918-1F3FB":{"unified":"1F918-1F3FB","image":"1f918-1f3fb.png","sheet_x":32,"sheet_y":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F918-1F3FC":{"unified":"1F918-1F3FC","image":"1f918-1f3fc.png","sheet_x":32,"sheet_y":10,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F918-1F3FD":{"unified":"1F918-1F3FD","image":"1f918-1f3fd.png","sheet_x":32,"sheet_y":11,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F918-1F3FE":{"unified":"1F918-1F3FE","image":"1f918-1f3fe.png","sheet_x":32,"sheet_y":12,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},"1F918-1F3FF":{"unified":"1F918-1F3FF","image":"1f918-1f3ff.png","sheet_x":32,"sheet_y":13,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true}}},{"name":"CRAB","unified":"1F980","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f980.png","sheet_x":32,"sheet_y":14,"short_name":"crab","short_names":["crab"],"text":null,"texts":null,"category":"Nature","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"LION FACE","unified":"1F981","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f981.png","sheet_x":32,"sheet_y":15,"short_name":"lion_face","short_names":["lion_face"],"text":null,"texts":null,"category":"Nature","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"SCORPION","unified":"1F982","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f982.png","sheet_x":32,"sheet_y":16,"short_name":"scorpion","short_names":["scorpion"],"text":null,"texts":null,"category":"Nature","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"TURKEY","unified":"1F983","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f983.png","sheet_x":32,"sheet_y":17,"short_name":"turkey","short_names":["turkey"],"text":null,"texts":null,"category":"Nature","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"UNICORN FACE","unified":"1F984","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f984.png","sheet_x":32,"sheet_y":18,"short_name":"unicorn_face","short_names":["unicorn_face"],"text":null,"texts":null,"category":"Nature","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"CHEESE WEDGE","unified":"1F9C0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f9c0.png","sheet_x":32,"sheet_y":19,"short_name":"cheese_wedge","short_names":["cheese_wedge"],"text":null,"texts":null,"category":"Foods","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"HASH KEY","unified":"0023-20E3","variations":["0023-FE0F-20E3"],"docomo":"E6E0","au":"EB84","softbank":"E210","google":"FE82C","image":"0023-20e3.png","sheet_x":32,"sheet_y":20,"short_name":"hash","short_names":["hash"],"text":null,"texts":null,"category":"Symbols","sort_order":178,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"002A-20E3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"002a-20e3.png","sheet_x":32,"sheet_y":21,"short_name":"keycap_star","short_names":["keycap_star"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 0","unified":"0030-20E3","variations":["0030-FE0F-20E3"],"docomo":"E6EB","au":"E5AC","softbank":"E225","google":"FE837","image":"0030-20e3.png","sheet_x":32,"sheet_y":22,"short_name":"zero","short_names":["zero"],"text":null,"texts":null,"category":"Symbols","sort_order":134,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 1","unified":"0031-20E3","variations":["0031-FE0F-20E3"],"docomo":"E6E2","au":"E522","softbank":"E21C","google":"FE82E","image":"0031-20e3.png","sheet_x":32,"sheet_y":23,"short_name":"one","short_names":["one"],"text":null,"texts":null,"category":"Symbols","sort_order":135,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 2","unified":"0032-20E3","variations":["0032-FE0F-20E3"],"docomo":"E6E3","au":"E523","softbank":"E21D","google":"FE82F","image":"0032-20e3.png","sheet_x":32,"sheet_y":24,"short_name":"two","short_names":["two"],"text":null,"texts":null,"category":"Symbols","sort_order":136,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 3","unified":"0033-20E3","variations":["0033-FE0F-20E3"],"docomo":"E6E4","au":"E524","softbank":"E21E","google":"FE830","image":"0033-20e3.png","sheet_x":32,"sheet_y":25,"short_name":"three","short_names":["three"],"text":null,"texts":null,"category":"Symbols","sort_order":137,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 4","unified":"0034-20E3","variations":["0034-FE0F-20E3"],"docomo":"E6E5","au":"E525","softbank":"E21F","google":"FE831","image":"0034-20e3.png","sheet_x":32,"sheet_y":26,"short_name":"four","short_names":["four"],"text":null,"texts":null,"category":"Symbols","sort_order":138,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 5","unified":"0035-20E3","variations":["0035-FE0F-20E3"],"docomo":"E6E6","au":"E526","softbank":"E220","google":"FE832","image":"0035-20e3.png","sheet_x":32,"sheet_y":27,"short_name":"five","short_names":["five"],"text":null,"texts":null,"category":"Symbols","sort_order":139,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 6","unified":"0036-20E3","variations":["0036-FE0F-20E3"],"docomo":"E6E7","au":"E527","softbank":"E221","google":"FE833","image":"0036-20e3.png","sheet_x":32,"sheet_y":28,"short_name":"six","short_names":["six"],"text":null,"texts":null,"category":"Symbols","sort_order":140,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 7","unified":"0037-20E3","variations":["0037-FE0F-20E3"],"docomo":"E6E8","au":"E528","softbank":"E222","google":"FE834","image":"0037-20e3.png","sheet_x":32,"sheet_y":29,"short_name":"seven","short_names":["seven"],"text":null,"texts":null,"category":"Symbols","sort_order":141,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 8","unified":"0038-20E3","variations":["0038-FE0F-20E3"],"docomo":"E6E9","au":"E529","softbank":"E223","google":"FE835","image":"0038-20e3.png","sheet_x":32,"sheet_y":30,"short_name":"eight","short_names":["eight"],"text":null,"texts":null,"category":"Symbols","sort_order":142,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"KEYCAP 9","unified":"0039-20E3","variations":["0039-FE0F-20E3"],"docomo":"E6EA","au":"E52A","softbank":"E224","google":"FE836","image":"0039-20e3.png","sheet_x":32,"sheet_y":31,"short_name":"nine","short_names":["nine"],"text":null,"texts":null,"category":"Symbols","sort_order":143,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AC","unified":"1F1E6-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1e8.png","sheet_x":32,"sheet_y":32,"short_name":"flag-ac","short_names":["flag-ac"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AD","unified":"1F1E6-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1e9.png","sheet_x":32,"sheet_y":33,"short_name":"flag-ad","short_names":["flag-ad"],"text":null,"texts":null,"category":"Flags","sort_order":6,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AE","unified":"1F1E6-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1ea.png","sheet_x":32,"sheet_y":34,"short_name":"flag-ae","short_names":["flag-ae"],"text":null,"texts":null,"category":"Flags","sort_order":233,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AF","unified":"1F1E6-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1eb.png","sheet_x":32,"sheet_y":35,"short_name":"flag-af","short_names":["flag-af"],"text":null,"texts":null,"category":"Flags","sort_order":1,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AG","unified":"1F1E6-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1ec.png","sheet_x":32,"sheet_y":36,"short_name":"flag-ag","short_names":["flag-ag"],"text":null,"texts":null,"category":"Flags","sort_order":10,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AI","unified":"1F1E6-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1ee.png","sheet_x":32,"sheet_y":37,"short_name":"flag-ai","short_names":["flag-ai"],"text":null,"texts":null,"category":"Flags","sort_order":8,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AL","unified":"1F1E6-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f1.png","sheet_x":32,"sheet_y":38,"short_name":"flag-al","short_names":["flag-al"],"text":null,"texts":null,"category":"Flags","sort_order":3,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AM","unified":"1F1E6-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f2.png","sheet_x":32,"sheet_y":39,"short_name":"flag-am","short_names":["flag-am"],"text":null,"texts":null,"category":"Flags","sort_order":12,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AO","unified":"1F1E6-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f4.png","sheet_x":32,"sheet_y":40,"short_name":"flag-ao","short_names":["flag-ao"],"text":null,"texts":null,"category":"Flags","sort_order":7,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AQ","unified":"1F1E6-1F1F6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f6.png","sheet_x":33,"sheet_y":0,"short_name":"flag-aq","short_names":["flag-aq"],"text":null,"texts":null,"category":"Flags","sort_order":9,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AR","unified":"1F1E6-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f7.png","sheet_x":33,"sheet_y":1,"short_name":"flag-ar","short_names":["flag-ar"],"text":null,"texts":null,"category":"Flags","sort_order":11,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AS","unified":"1F1E6-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f8.png","sheet_x":33,"sheet_y":2,"short_name":"flag-as","short_names":["flag-as"],"text":null,"texts":null,"category":"Flags","sort_order":5,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AT","unified":"1F1E6-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1f9.png","sheet_x":33,"sheet_y":3,"short_name":"flag-at","short_names":["flag-at"],"text":null,"texts":null,"category":"Flags","sort_order":15,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AU","unified":"1F1E6-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1fa.png","sheet_x":33,"sheet_y":4,"short_name":"flag-au","short_names":["flag-au"],"text":null,"texts":null,"category":"Flags","sort_order":14,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AW","unified":"1F1E6-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1fc.png","sheet_x":33,"sheet_y":5,"short_name":"flag-aw","short_names":["flag-aw"],"text":null,"texts":null,"category":"Flags","sort_order":13,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AX","unified":"1F1E6-1F1FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1fd.png","sheet_x":33,"sheet_y":6,"short_name":"flag-ax","short_names":["flag-ax"],"text":null,"texts":null,"category":"Flags","sort_order":2,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS AZ","unified":"1F1E6-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e6-1f1ff.png","sheet_x":33,"sheet_y":7,"short_name":"flag-az","short_names":["flag-az"],"text":null,"texts":null,"category":"Flags","sort_order":16,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BA","unified":"1F1E7-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1e6.png","sheet_x":33,"sheet_y":8,"short_name":"flag-ba","short_names":["flag-ba"],"text":null,"texts":null,"category":"Flags","sort_order":29,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BB","unified":"1F1E7-1F1E7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1e7.png","sheet_x":33,"sheet_y":9,"short_name":"flag-bb","short_names":["flag-bb"],"text":null,"texts":null,"category":"Flags","sort_order":20,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BD","unified":"1F1E7-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1e9.png","sheet_x":33,"sheet_y":10,"short_name":"flag-bd","short_names":["flag-bd"],"text":null,"texts":null,"category":"Flags","sort_order":19,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BE","unified":"1F1E7-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ea.png","sheet_x":33,"sheet_y":11,"short_name":"flag-be","short_names":["flag-be"],"text":null,"texts":null,"category":"Flags","sort_order":22,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BF","unified":"1F1E7-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1eb.png","sheet_x":33,"sheet_y":12,"short_name":"flag-bf","short_names":["flag-bf"],"text":null,"texts":null,"category":"Flags","sort_order":36,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BG","unified":"1F1E7-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ec.png","sheet_x":33,"sheet_y":13,"short_name":"flag-bg","short_names":["flag-bg"],"text":null,"texts":null,"category":"Flags","sort_order":35,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BH","unified":"1F1E7-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ed.png","sheet_x":33,"sheet_y":14,"short_name":"flag-bh","short_names":["flag-bh"],"text":null,"texts":null,"category":"Flags","sort_order":18,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BI","unified":"1F1E7-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ee.png","sheet_x":33,"sheet_y":15,"short_name":"flag-bi","short_names":["flag-bi"],"text":null,"texts":null,"category":"Flags","sort_order":37,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BJ","unified":"1F1E7-1F1EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ef.png","sheet_x":33,"sheet_y":16,"short_name":"flag-bj","short_names":["flag-bj"],"text":null,"texts":null,"category":"Flags","sort_order":24,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BL","unified":"1F1E7-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f1.png","sheet_x":33,"sheet_y":17,"short_name":"flag-bl","short_names":["flag-bl"],"text":null,"texts":null,"category":"Flags","sort_order":185,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BM","unified":"1F1E7-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f2.png","sheet_x":33,"sheet_y":18,"short_name":"flag-bm","short_names":["flag-bm"],"text":null,"texts":null,"category":"Flags","sort_order":25,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BN","unified":"1F1E7-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f3.png","sheet_x":33,"sheet_y":19,"short_name":"flag-bn","short_names":["flag-bn"],"text":null,"texts":null,"category":"Flags","sort_order":34,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BO","unified":"1F1E7-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f4.png","sheet_x":33,"sheet_y":20,"short_name":"flag-bo","short_names":["flag-bo"],"text":null,"texts":null,"category":"Flags","sort_order":27,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BQ","unified":"1F1E7-1F1F6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f6.png","sheet_x":33,"sheet_y":21,"short_name":"flag-bq","short_names":["flag-bq"],"text":null,"texts":null,"category":"Flags","sort_order":28,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BR","unified":"1F1E7-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f7.png","sheet_x":33,"sheet_y":22,"short_name":"flag-br","short_names":["flag-br"],"text":null,"texts":null,"category":"Flags","sort_order":31,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BS","unified":"1F1E7-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f8.png","sheet_x":33,"sheet_y":23,"short_name":"flag-bs","short_names":["flag-bs"],"text":null,"texts":null,"category":"Flags","sort_order":17,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BT","unified":"1F1E7-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1f9.png","sheet_x":33,"sheet_y":24,"short_name":"flag-bt","short_names":["flag-bt"],"text":null,"texts":null,"category":"Flags","sort_order":26,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BV","unified":"1F1E7-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1fb.png","sheet_x":33,"sheet_y":25,"short_name":"flag-bv","short_names":["flag-bv"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BW","unified":"1F1E7-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1fc.png","sheet_x":33,"sheet_y":26,"short_name":"flag-bw","short_names":["flag-bw"],"text":null,"texts":null,"category":"Flags","sort_order":30,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BY","unified":"1F1E7-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1fe.png","sheet_x":33,"sheet_y":27,"short_name":"flag-by","short_names":["flag-by"],"text":null,"texts":null,"category":"Flags","sort_order":21,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS BZ","unified":"1F1E7-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e7-1f1ff.png","sheet_x":33,"sheet_y":28,"short_name":"flag-bz","short_names":["flag-bz"],"text":null,"texts":null,"category":"Flags","sort_order":23,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CA","unified":"1F1E8-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1e6.png","sheet_x":33,"sheet_y":29,"short_name":"flag-ca","short_names":["flag-ca"],"text":null,"texts":null,"category":"Flags","sort_order":41,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CC","unified":"1F1E8-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1e8.png","sheet_x":33,"sheet_y":30,"short_name":"flag-cc","short_names":["flag-cc"],"text":null,"texts":null,"category":"Flags","sort_order":49,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CD","unified":"1F1E8-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1e9.png","sheet_x":33,"sheet_y":31,"short_name":"flag-cd","short_names":["flag-cd"],"text":null,"texts":null,"category":"Flags","sort_order":53,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CF","unified":"1F1E8-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1eb.png","sheet_x":33,"sheet_y":32,"short_name":"flag-cf","short_names":["flag-cf"],"text":null,"texts":null,"category":"Flags","sort_order":44,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CG","unified":"1F1E8-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1ec.png","sheet_x":33,"sheet_y":33,"short_name":"flag-cg","short_names":["flag-cg"],"text":null,"texts":null,"category":"Flags","sort_order":52,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CH","unified":"1F1E8-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1ed.png","sheet_x":33,"sheet_y":34,"short_name":"flag-ch","short_names":["flag-ch"],"text":null,"texts":null,"category":"Flags","sort_order":215,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CI","unified":"1F1E8-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1ee.png","sheet_x":33,"sheet_y":35,"short_name":"flag-ci","short_names":["flag-ci"],"text":null,"texts":null,"category":"Flags","sort_order":110,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CK","unified":"1F1E8-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f0.png","sheet_x":33,"sheet_y":36,"short_name":"flag-ck","short_names":["flag-ck"],"text":null,"texts":null,"category":"Flags","sort_order":54,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CL","unified":"1F1E8-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f1.png","sheet_x":33,"sheet_y":37,"short_name":"flag-cl","short_names":["flag-cl"],"text":null,"texts":null,"category":"Flags","sort_order":46,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CM","unified":"1F1E8-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f2.png","sheet_x":33,"sheet_y":38,"short_name":"flag-cm","short_names":["flag-cm"],"text":null,"texts":null,"category":"Flags","sort_order":40,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CN","unified":"1F1E8-1F1F3","variations":[],"docomo":null,"au":"EB11","softbank":"E513","google":"FE4ED","image":"1f1e8-1f1f3.png","sheet_x":33,"sheet_y":39,"short_name":"flag-cn","short_names":["flag-cn","cn"],"text":null,"texts":null,"category":"Flags","sort_order":47,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CO","unified":"1F1E8-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f4.png","sheet_x":33,"sheet_y":40,"short_name":"flag-co","short_names":["flag-co"],"text":null,"texts":null,"category":"Flags","sort_order":50,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CP","unified":"1F1E8-1F1F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f5.png","sheet_x":34,"sheet_y":0,"short_name":"flag-cp","short_names":["flag-cp"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CR","unified":"1F1E8-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1f7.png","sheet_x":34,"sheet_y":1,"short_name":"flag-cr","short_names":["flag-cr"],"text":null,"texts":null,"category":"Flags","sort_order":55,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CU","unified":"1F1E8-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1fa.png","sheet_x":34,"sheet_y":2,"short_name":"flag-cu","short_names":["flag-cu"],"text":null,"texts":null,"category":"Flags","sort_order":57,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CV","unified":"1F1E8-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1fb.png","sheet_x":34,"sheet_y":3,"short_name":"flag-cv","short_names":["flag-cv"],"text":null,"texts":null,"category":"Flags","sort_order":38,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CW","unified":"1F1E8-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1fc.png","sheet_x":34,"sheet_y":4,"short_name":"flag-cw","short_names":["flag-cw"],"text":null,"texts":null,"category":"Flags","sort_order":58,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CX","unified":"1F1E8-1F1FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1fd.png","sheet_x":34,"sheet_y":5,"short_name":"flag-cx","short_names":["flag-cx"],"text":null,"texts":null,"category":"Flags","sort_order":48,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CY","unified":"1F1E8-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1fe.png","sheet_x":34,"sheet_y":6,"short_name":"flag-cy","short_names":["flag-cy"],"text":null,"texts":null,"category":"Flags","sort_order":59,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS CZ","unified":"1F1E8-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e8-1f1ff.png","sheet_x":34,"sheet_y":7,"short_name":"flag-cz","short_names":["flag-cz"],"text":null,"texts":null,"category":"Flags","sort_order":60,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DE","unified":"1F1E9-1F1EA","variations":[],"docomo":null,"au":"EB0E","softbank":"E50E","google":"FE4E8","image":"1f1e9-1f1ea.png","sheet_x":34,"sheet_y":8,"short_name":"flag-de","short_names":["flag-de","de"],"text":null,"texts":null,"category":"Flags","sort_order":84,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DG","unified":"1F1E9-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1ec.png","sheet_x":34,"sheet_y":9,"short_name":"flag-dg","short_names":["flag-dg"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DJ","unified":"1F1E9-1F1EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1ef.png","sheet_x":34,"sheet_y":10,"short_name":"flag-dj","short_names":["flag-dj"],"text":null,"texts":null,"category":"Flags","sort_order":62,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DK","unified":"1F1E9-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1f0.png","sheet_x":34,"sheet_y":11,"short_name":"flag-dk","short_names":["flag-dk"],"text":null,"texts":null,"category":"Flags","sort_order":61,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DM","unified":"1F1E9-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1f2.png","sheet_x":34,"sheet_y":12,"short_name":"flag-dm","short_names":["flag-dm"],"text":null,"texts":null,"category":"Flags","sort_order":63,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DO","unified":"1F1E9-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1f4.png","sheet_x":34,"sheet_y":13,"short_name":"flag-do","short_names":["flag-do"],"text":null,"texts":null,"category":"Flags","sort_order":64,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS DZ","unified":"1F1E9-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1e9-1f1ff.png","sheet_x":34,"sheet_y":14,"short_name":"flag-dz","short_names":["flag-dz"],"text":null,"texts":null,"category":"Flags","sort_order":4,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EA","unified":"1F1EA-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1e6.png","sheet_x":34,"sheet_y":15,"short_name":"flag-ea","short_names":["flag-ea"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EC","unified":"1F1EA-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1e8.png","sheet_x":34,"sheet_y":16,"short_name":"flag-ec","short_names":["flag-ec"],"text":null,"texts":null,"category":"Flags","sort_order":65,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EE","unified":"1F1EA-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1ea.png","sheet_x":34,"sheet_y":17,"short_name":"flag-ee","short_names":["flag-ee"],"text":null,"texts":null,"category":"Flags","sort_order":70,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EG","unified":"1F1EA-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1ec.png","sheet_x":34,"sheet_y":18,"short_name":"flag-eg","short_names":["flag-eg"],"text":null,"texts":null,"category":"Flags","sort_order":66,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EH","unified":"1F1EA-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1ed.png","sheet_x":34,"sheet_y":19,"short_name":"flag-eh","short_names":["flag-eh"],"text":null,"texts":null,"category":"Flags","sort_order":244,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ER","unified":"1F1EA-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1f7.png","sheet_x":34,"sheet_y":20,"short_name":"flag-er","short_names":["flag-er"],"text":null,"texts":null,"category":"Flags","sort_order":69,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ES","unified":"1F1EA-1F1F8","variations":[],"docomo":null,"au":"E5D5","softbank":"E511","google":"FE4EB","image":"1f1ea-1f1f8.png","sheet_x":34,"sheet_y":21,"short_name":"flag-es","short_names":["flag-es","es"],"text":null,"texts":null,"category":"Flags","sort_order":209,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ET","unified":"1F1EA-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1f9.png","sheet_x":34,"sheet_y":22,"short_name":"flag-et","short_names":["flag-et"],"text":null,"texts":null,"category":"Flags","sort_order":71,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS EU","unified":"1F1EA-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ea-1f1fa.png","sheet_x":34,"sheet_y":23,"short_name":"flag-eu","short_names":["flag-eu"],"text":null,"texts":null,"category":"Flags","sort_order":72,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FI","unified":"1F1EB-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1eb-1f1ee.png","sheet_x":34,"sheet_y":24,"short_name":"flag-fi","short_names":["flag-fi"],"text":null,"texts":null,"category":"Flags","sort_order":76,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FJ","unified":"1F1EB-1F1EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1eb-1f1ef.png","sheet_x":34,"sheet_y":25,"short_name":"flag-fj","short_names":["flag-fj"],"text":null,"texts":null,"category":"Flags","sort_order":75,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FK","unified":"1F1EB-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1eb-1f1f0.png","sheet_x":34,"sheet_y":26,"short_name":"flag-fk","short_names":["flag-fk"],"text":null,"texts":null,"category":"Flags","sort_order":73,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FM","unified":"1F1EB-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1eb-1f1f2.png","sheet_x":34,"sheet_y":27,"short_name":"flag-fm","short_names":["flag-fm"],"text":null,"texts":null,"category":"Flags","sort_order":144,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FO","unified":"1F1EB-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1eb-1f1f4.png","sheet_x":34,"sheet_y":28,"short_name":"flag-fo","short_names":["flag-fo"],"text":null,"texts":null,"category":"Flags","sort_order":74,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS FR","unified":"1F1EB-1F1F7","variations":[],"docomo":null,"au":"EAFA","softbank":"E50D","google":"FE4E7","image":"1f1eb-1f1f7.png","sheet_x":34,"sheet_y":29,"short_name":"flag-fr","short_names":["flag-fr","fr"],"text":null,"texts":null,"category":"Flags","sort_order":77,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GA","unified":"1F1EC-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1e6.png","sheet_x":34,"sheet_y":30,"short_name":"flag-ga","short_names":["flag-ga"],"text":null,"texts":null,"category":"Flags","sort_order":81,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GB","unified":"1F1EC-1F1E7","variations":[],"docomo":null,"au":"EB10","softbank":"E510","google":"FE4EA","image":"1f1ec-1f1e7.png","sheet_x":34,"sheet_y":31,"short_name":"flag-gb","short_names":["flag-gb","gb","uk"],"text":null,"texts":null,"category":"Flags","sort_order":234,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GD","unified":"1F1EC-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1e9.png","sheet_x":34,"sheet_y":32,"short_name":"flag-gd","short_names":["flag-gd"],"text":null,"texts":null,"category":"Flags","sort_order":89,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GE","unified":"1F1EC-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1ea.png","sheet_x":34,"sheet_y":33,"short_name":"flag-ge","short_names":["flag-ge"],"text":null,"texts":null,"category":"Flags","sort_order":83,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GF","unified":"1F1EC-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1eb.png","sheet_x":34,"sheet_y":34,"short_name":"flag-gf","short_names":["flag-gf"],"text":null,"texts":null,"category":"Flags","sort_order":78,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GG","unified":"1F1EC-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1ec.png","sheet_x":34,"sheet_y":35,"short_name":"flag-gg","short_names":["flag-gg"],"text":null,"texts":null,"category":"Flags","sort_order":93,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GH","unified":"1F1EC-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1ed.png","sheet_x":34,"sheet_y":36,"short_name":"flag-gh","short_names":["flag-gh"],"text":null,"texts":null,"category":"Flags","sort_order":85,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GI","unified":"1F1EC-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1ee.png","sheet_x":34,"sheet_y":37,"short_name":"flag-gi","short_names":["flag-gi"],"text":null,"texts":null,"category":"Flags","sort_order":86,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GL","unified":"1F1EC-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f1.png","sheet_x":34,"sheet_y":38,"short_name":"flag-gl","short_names":["flag-gl"],"text":null,"texts":null,"category":"Flags","sort_order":88,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GM","unified":"1F1EC-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f2.png","sheet_x":34,"sheet_y":39,"short_name":"flag-gm","short_names":["flag-gm"],"text":null,"texts":null,"category":"Flags","sort_order":82,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GN","unified":"1F1EC-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f3.png","sheet_x":34,"sheet_y":40,"short_name":"flag-gn","short_names":["flag-gn"],"text":null,"texts":null,"category":"Flags","sort_order":94,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GP","unified":"1F1EC-1F1F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f5.png","sheet_x":35,"sheet_y":0,"short_name":"flag-gp","short_names":["flag-gp"],"text":null,"texts":null,"category":"Flags","sort_order":90,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GQ","unified":"1F1EC-1F1F6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f6.png","sheet_x":35,"sheet_y":1,"short_name":"flag-gq","short_names":["flag-gq"],"text":null,"texts":null,"category":"Flags","sort_order":68,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GR","unified":"1F1EC-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f7.png","sheet_x":35,"sheet_y":2,"short_name":"flag-gr","short_names":["flag-gr"],"text":null,"texts":null,"category":"Flags","sort_order":87,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GS","unified":"1F1EC-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f8.png","sheet_x":35,"sheet_y":3,"short_name":"flag-gs","short_names":["flag-gs"],"text":null,"texts":null,"category":"Flags","sort_order":206,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GT","unified":"1F1EC-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1f9.png","sheet_x":35,"sheet_y":4,"short_name":"flag-gt","short_names":["flag-gt"],"text":null,"texts":null,"category":"Flags","sort_order":92,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GU","unified":"1F1EC-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1fa.png","sheet_x":35,"sheet_y":5,"short_name":"flag-gu","short_names":["flag-gu"],"text":null,"texts":null,"category":"Flags","sort_order":91,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GW","unified":"1F1EC-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1fc.png","sheet_x":35,"sheet_y":6,"short_name":"flag-gw","short_names":["flag-gw"],"text":null,"texts":null,"category":"Flags","sort_order":95,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS GY","unified":"1F1EC-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ec-1f1fe.png","sheet_x":35,"sheet_y":7,"short_name":"flag-gy","short_names":["flag-gy"],"text":null,"texts":null,"category":"Flags","sort_order":96,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HK","unified":"1F1ED-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1f0.png","sheet_x":35,"sheet_y":8,"short_name":"flag-hk","short_names":["flag-hk"],"text":null,"texts":null,"category":"Flags","sort_order":99,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HM","unified":"1F1ED-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1f2.png","sheet_x":35,"sheet_y":9,"short_name":"flag-hm","short_names":["flag-hm"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HN","unified":"1F1ED-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1f3.png","sheet_x":35,"sheet_y":10,"short_name":"flag-hn","short_names":["flag-hn"],"text":null,"texts":null,"category":"Flags","sort_order":98,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HR","unified":"1F1ED-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1f7.png","sheet_x":35,"sheet_y":11,"short_name":"flag-hr","short_names":["flag-hr"],"text":null,"texts":null,"category":"Flags","sort_order":56,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HT","unified":"1F1ED-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1f9.png","sheet_x":35,"sheet_y":12,"short_name":"flag-ht","short_names":["flag-ht"],"text":null,"texts":null,"category":"Flags","sort_order":97,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS HU","unified":"1F1ED-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ed-1f1fa.png","sheet_x":35,"sheet_y":13,"short_name":"flag-hu","short_names":["flag-hu"],"text":null,"texts":null,"category":"Flags","sort_order":100,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IC","unified":"1F1EE-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1e8.png","sheet_x":35,"sheet_y":14,"short_name":"flag-ic","short_names":["flag-ic"],"text":null,"texts":null,"category":"Flags","sort_order":42,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ID","unified":"1F1EE-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1e9.png","sheet_x":35,"sheet_y":15,"short_name":"flag-id","short_names":["flag-id"],"text":null,"texts":null,"category":"Flags","sort_order":103,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IE","unified":"1F1EE-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1ea.png","sheet_x":35,"sheet_y":16,"short_name":"flag-ie","short_names":["flag-ie"],"text":null,"texts":null,"category":"Flags","sort_order":106,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IL","unified":"1F1EE-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f1.png","sheet_x":35,"sheet_y":17,"short_name":"flag-il","short_names":["flag-il"],"text":null,"texts":null,"category":"Flags","sort_order":108,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IM","unified":"1F1EE-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f2.png","sheet_x":35,"sheet_y":18,"short_name":"flag-im","short_names":["flag-im"],"text":null,"texts":null,"category":"Flags","sort_order":107,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IN","unified":"1F1EE-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f3.png","sheet_x":35,"sheet_y":19,"short_name":"flag-in","short_names":["flag-in"],"text":null,"texts":null,"category":"Flags","sort_order":102,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IO","unified":"1F1EE-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f4.png","sheet_x":35,"sheet_y":20,"short_name":"flag-io","short_names":["flag-io"],"text":null,"texts":null,"category":"Flags","sort_order":32,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IQ","unified":"1F1EE-1F1F6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f6.png","sheet_x":35,"sheet_y":21,"short_name":"flag-iq","short_names":["flag-iq"],"text":null,"texts":null,"category":"Flags","sort_order":105,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IR","unified":"1F1EE-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f7.png","sheet_x":35,"sheet_y":22,"short_name":"flag-ir","short_names":["flag-ir"],"text":null,"texts":null,"category":"Flags","sort_order":104,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IS","unified":"1F1EE-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ee-1f1f8.png","sheet_x":35,"sheet_y":23,"short_name":"flag-is","short_names":["flag-is"],"text":null,"texts":null,"category":"Flags","sort_order":101,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS IT","unified":"1F1EE-1F1F9","variations":[],"docomo":null,"au":"EB0F","softbank":"E50F","google":"FE4E9","image":"1f1ee-1f1f9.png","sheet_x":35,"sheet_y":24,"short_name":"flag-it","short_names":["flag-it","it"],"text":null,"texts":null,"category":"Flags","sort_order":109,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS JE","unified":"1F1EF-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ef-1f1ea.png","sheet_x":35,"sheet_y":25,"short_name":"flag-je","short_names":["flag-je"],"text":null,"texts":null,"category":"Flags","sort_order":113,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS JM","unified":"1F1EF-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ef-1f1f2.png","sheet_x":35,"sheet_y":26,"short_name":"flag-jm","short_names":["flag-jm"],"text":null,"texts":null,"category":"Flags","sort_order":111,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS JO","unified":"1F1EF-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ef-1f1f4.png","sheet_x":35,"sheet_y":27,"short_name":"flag-jo","short_names":["flag-jo"],"text":null,"texts":null,"category":"Flags","sort_order":114,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS JP","unified":"1F1EF-1F1F5","variations":[],"docomo":null,"au":"E4CC","softbank":"E50B","google":"FE4E5","image":"1f1ef-1f1f5.png","sheet_x":35,"sheet_y":28,"short_name":"flag-jp","short_names":["flag-jp","jp"],"text":null,"texts":null,"category":"Flags","sort_order":112,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KE","unified":"1F1F0-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1ea.png","sheet_x":35,"sheet_y":29,"short_name":"flag-ke","short_names":["flag-ke"],"text":null,"texts":null,"category":"Flags","sort_order":116,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KG","unified":"1F1F0-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1ec.png","sheet_x":35,"sheet_y":30,"short_name":"flag-kg","short_names":["flag-kg"],"text":null,"texts":null,"category":"Flags","sort_order":120,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KH","unified":"1F1F0-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1ed.png","sheet_x":35,"sheet_y":31,"short_name":"flag-kh","short_names":["flag-kh"],"text":null,"texts":null,"category":"Flags","sort_order":39,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KI","unified":"1F1F0-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1ee.png","sheet_x":35,"sheet_y":32,"short_name":"flag-ki","short_names":["flag-ki"],"text":null,"texts":null,"category":"Flags","sort_order":117,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KM","unified":"1F1F0-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1f2.png","sheet_x":35,"sheet_y":33,"short_name":"flag-km","short_names":["flag-km"],"text":null,"texts":null,"category":"Flags","sort_order":51,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KN","unified":"1F1F0-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1f3.png","sheet_x":35,"sheet_y":34,"short_name":"flag-kn","short_names":["flag-kn"],"text":null,"texts":null,"category":"Flags","sort_order":187,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KP","unified":"1F1F0-1F1F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1f5.png","sheet_x":35,"sheet_y":35,"short_name":"flag-kp","short_names":["flag-kp"],"text":null,"texts":null,"category":"Flags","sort_order":165,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KR","unified":"1F1F0-1F1F7","variations":[],"docomo":null,"au":"EB12","softbank":"E514","google":"FE4EE","image":"1f1f0-1f1f7.png","sheet_x":35,"sheet_y":36,"short_name":"flag-kr","short_names":["flag-kr","kr"],"text":null,"texts":null,"category":"Flags","sort_order":207,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KW","unified":"1F1F0-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1fc.png","sheet_x":35,"sheet_y":37,"short_name":"flag-kw","short_names":["flag-kw"],"text":null,"texts":null,"category":"Flags","sort_order":119,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KY","unified":"1F1F0-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1fe.png","sheet_x":35,"sheet_y":38,"short_name":"flag-ky","short_names":["flag-ky"],"text":null,"texts":null,"category":"Flags","sort_order":43,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS KZ","unified":"1F1F0-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f0-1f1ff.png","sheet_x":35,"sheet_y":39,"short_name":"flag-kz","short_names":["flag-kz"],"text":null,"texts":null,"category":"Flags","sort_order":115,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LA","unified":"1F1F1-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1e6.png","sheet_x":35,"sheet_y":40,"short_name":"flag-la","short_names":["flag-la"],"text":null,"texts":null,"category":"Flags","sort_order":121,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LB","unified":"1F1F1-1F1E7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1e7.png","sheet_x":36,"sheet_y":0,"short_name":"flag-lb","short_names":["flag-lb"],"text":null,"texts":null,"category":"Flags","sort_order":123,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LC","unified":"1F1F1-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1e8.png","sheet_x":36,"sheet_y":1,"short_name":"flag-lc","short_names":["flag-lc"],"text":null,"texts":null,"category":"Flags","sort_order":188,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LI","unified":"1F1F1-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1ee.png","sheet_x":36,"sheet_y":2,"short_name":"flag-li","short_names":["flag-li"],"text":null,"texts":null,"category":"Flags","sort_order":127,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LK","unified":"1F1F1-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1f0.png","sheet_x":36,"sheet_y":3,"short_name":"flag-lk","short_names":["flag-lk"],"text":null,"texts":null,"category":"Flags","sort_order":210,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LR","unified":"1F1F1-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1f7.png","sheet_x":36,"sheet_y":4,"short_name":"flag-lr","short_names":["flag-lr"],"text":null,"texts":null,"category":"Flags","sort_order":125,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LS","unified":"1F1F1-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1f8.png","sheet_x":36,"sheet_y":5,"short_name":"flag-ls","short_names":["flag-ls"],"text":null,"texts":null,"category":"Flags","sort_order":124,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LT","unified":"1F1F1-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1f9.png","sheet_x":36,"sheet_y":6,"short_name":"flag-lt","short_names":["flag-lt"],"text":null,"texts":null,"category":"Flags","sort_order":128,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LU","unified":"1F1F1-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1fa.png","sheet_x":36,"sheet_y":7,"short_name":"flag-lu","short_names":["flag-lu"],"text":null,"texts":null,"category":"Flags","sort_order":129,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LV","unified":"1F1F1-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1fb.png","sheet_x":36,"sheet_y":8,"short_name":"flag-lv","short_names":["flag-lv"],"text":null,"texts":null,"category":"Flags","sort_order":122,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS LY","unified":"1F1F1-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f1-1f1fe.png","sheet_x":36,"sheet_y":9,"short_name":"flag-ly","short_names":["flag-ly"],"text":null,"texts":null,"category":"Flags","sort_order":126,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MA","unified":"1F1F2-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1e6.png","sheet_x":36,"sheet_y":10,"short_name":"flag-ma","short_names":["flag-ma"],"text":null,"texts":null,"category":"Flags","sort_order":150,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MC","unified":"1F1F2-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1e8.png","sheet_x":36,"sheet_y":11,"short_name":"flag-mc","short_names":["flag-mc"],"text":null,"texts":null,"category":"Flags","sort_order":146,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MD","unified":"1F1F2-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1e9.png","sheet_x":36,"sheet_y":12,"short_name":"flag-md","short_names":["flag-md"],"text":null,"texts":null,"category":"Flags","sort_order":145,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ME","unified":"1F1F2-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1ea.png","sheet_x":36,"sheet_y":13,"short_name":"flag-me","short_names":["flag-me"],"text":null,"texts":null,"category":"Flags","sort_order":148,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MF","unified":"1F1F2-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1eb.png","sheet_x":36,"sheet_y":14,"short_name":"flag-mf","short_names":["flag-mf"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MG","unified":"1F1F2-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1ec.png","sheet_x":36,"sheet_y":15,"short_name":"flag-mg","short_names":["flag-mg"],"text":null,"texts":null,"category":"Flags","sort_order":132,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MH","unified":"1F1F2-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1ed.png","sheet_x":36,"sheet_y":16,"short_name":"flag-mh","short_names":["flag-mh"],"text":null,"texts":null,"category":"Flags","sort_order":138,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MK","unified":"1F1F2-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f0.png","sheet_x":36,"sheet_y":17,"short_name":"flag-mk","short_names":["flag-mk"],"text":null,"texts":null,"category":"Flags","sort_order":131,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ML","unified":"1F1F2-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f1.png","sheet_x":36,"sheet_y":18,"short_name":"flag-ml","short_names":["flag-ml"],"text":null,"texts":null,"category":"Flags","sort_order":136,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MM","unified":"1F1F2-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f2.png","sheet_x":36,"sheet_y":19,"short_name":"flag-mm","short_names":["flag-mm"],"text":null,"texts":null,"category":"Flags","sort_order":152,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MN","unified":"1F1F2-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f3.png","sheet_x":36,"sheet_y":20,"short_name":"flag-mn","short_names":["flag-mn"],"text":null,"texts":null,"category":"Flags","sort_order":147,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MO","unified":"1F1F2-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f4.png","sheet_x":36,"sheet_y":21,"short_name":"flag-mo","short_names":["flag-mo"],"text":null,"texts":null,"category":"Flags","sort_order":130,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MP","unified":"1F1F2-1F1F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f5.png","sheet_x":36,"sheet_y":22,"short_name":"flag-mp","short_names":["flag-mp"],"text":null,"texts":null,"category":"Flags","sort_order":164,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MQ","unified":"1F1F2-1F1F6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f6.png","sheet_x":36,"sheet_y":23,"short_name":"flag-mq","short_names":["flag-mq"],"text":null,"texts":null,"category":"Flags","sort_order":139,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MR","unified":"1F1F2-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f7.png","sheet_x":36,"sheet_y":24,"short_name":"flag-mr","short_names":["flag-mr"],"text":null,"texts":null,"category":"Flags","sort_order":140,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MS","unified":"1F1F2-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f8.png","sheet_x":36,"sheet_y":25,"short_name":"flag-ms","short_names":["flag-ms"],"text":null,"texts":null,"category":"Flags","sort_order":149,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MT","unified":"1F1F2-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1f9.png","sheet_x":36,"sheet_y":26,"short_name":"flag-mt","short_names":["flag-mt"],"text":null,"texts":null,"category":"Flags","sort_order":137,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MU","unified":"1F1F2-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1fa.png","sheet_x":36,"sheet_y":27,"short_name":"flag-mu","short_names":["flag-mu"],"text":null,"texts":null,"category":"Flags","sort_order":141,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MV","unified":"1F1F2-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1fb.png","sheet_x":36,"sheet_y":28,"short_name":"flag-mv","short_names":["flag-mv"],"text":null,"texts":null,"category":"Flags","sort_order":135,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MW","unified":"1F1F2-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1fc.png","sheet_x":36,"sheet_y":29,"short_name":"flag-mw","short_names":["flag-mw"],"text":null,"texts":null,"category":"Flags","sort_order":133,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MX","unified":"1F1F2-1F1FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1fd.png","sheet_x":36,"sheet_y":30,"short_name":"flag-mx","short_names":["flag-mx"],"text":null,"texts":null,"category":"Flags","sort_order":143,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MY","unified":"1F1F2-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1fe.png","sheet_x":36,"sheet_y":31,"short_name":"flag-my","short_names":["flag-my"],"text":null,"texts":null,"category":"Flags","sort_order":134,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS MZ","unified":"1F1F2-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f2-1f1ff.png","sheet_x":36,"sheet_y":32,"short_name":"flag-mz","short_names":["flag-mz"],"text":null,"texts":null,"category":"Flags","sort_order":151,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NA","unified":"1F1F3-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1e6.png","sheet_x":36,"sheet_y":33,"short_name":"flag-na","short_names":["flag-na"],"text":null,"texts":null,"category":"Flags","sort_order":153,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NC","unified":"1F1F3-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1e8.png","sheet_x":36,"sheet_y":34,"short_name":"flag-nc","short_names":["flag-nc"],"text":null,"texts":null,"category":"Flags","sort_order":157,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NE","unified":"1F1F3-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1ea.png","sheet_x":36,"sheet_y":35,"short_name":"flag-ne","short_names":["flag-ne"],"text":null,"texts":null,"category":"Flags","sort_order":160,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NF","unified":"1F1F3-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1eb.png","sheet_x":36,"sheet_y":36,"short_name":"flag-nf","short_names":["flag-nf"],"text":null,"texts":null,"category":"Flags","sort_order":163,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NG","unified":"1F1F3-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1ec.png","sheet_x":36,"sheet_y":37,"short_name":"flag-ng","short_names":["flag-ng"],"text":null,"texts":null,"category":"Flags","sort_order":161,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NI","unified":"1F1F3-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1ee.png","sheet_x":36,"sheet_y":38,"short_name":"flag-ni","short_names":["flag-ni"],"text":null,"texts":null,"category":"Flags","sort_order":159,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NL","unified":"1F1F3-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1f1.png","sheet_x":36,"sheet_y":39,"short_name":"flag-nl","short_names":["flag-nl"],"text":null,"texts":null,"category":"Flags","sort_order":156,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NO","unified":"1F1F3-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1f4.png","sheet_x":36,"sheet_y":40,"short_name":"flag-no","short_names":["flag-no"],"text":null,"texts":null,"category":"Flags","sort_order":166,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NP","unified":"1F1F3-1F1F5","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1f5.png","sheet_x":37,"sheet_y":0,"short_name":"flag-np","short_names":["flag-np"],"text":null,"texts":null,"category":"Flags","sort_order":155,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NR","unified":"1F1F3-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1f7.png","sheet_x":37,"sheet_y":1,"short_name":"flag-nr","short_names":["flag-nr"],"text":null,"texts":null,"category":"Flags","sort_order":154,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NU","unified":"1F1F3-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1fa.png","sheet_x":37,"sheet_y":2,"short_name":"flag-nu","short_names":["flag-nu"],"text":null,"texts":null,"category":"Flags","sort_order":162,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS NZ","unified":"1F1F3-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f3-1f1ff.png","sheet_x":37,"sheet_y":3,"short_name":"flag-nz","short_names":["flag-nz"],"text":null,"texts":null,"category":"Flags","sort_order":158,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS OM","unified":"1F1F4-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f4-1f1f2.png","sheet_x":37,"sheet_y":4,"short_name":"flag-om","short_names":["flag-om"],"text":null,"texts":null,"category":"Flags","sort_order":167,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PA","unified":"1F1F5-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1e6.png","sheet_x":37,"sheet_y":5,"short_name":"flag-pa","short_names":["flag-pa"],"text":null,"texts":null,"category":"Flags","sort_order":171,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PE","unified":"1F1F5-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1ea.png","sheet_x":37,"sheet_y":6,"short_name":"flag-pe","short_names":["flag-pe"],"text":null,"texts":null,"category":"Flags","sort_order":174,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PF","unified":"1F1F5-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1eb.png","sheet_x":37,"sheet_y":7,"short_name":"flag-pf","short_names":["flag-pf"],"text":null,"texts":null,"category":"Flags","sort_order":79,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PG","unified":"1F1F5-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1ec.png","sheet_x":37,"sheet_y":8,"short_name":"flag-pg","short_names":["flag-pg"],"text":null,"texts":null,"category":"Flags","sort_order":172,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PH","unified":"1F1F5-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1ed.png","sheet_x":37,"sheet_y":9,"short_name":"flag-ph","short_names":["flag-ph"],"text":null,"texts":null,"category":"Flags","sort_order":175,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PK","unified":"1F1F5-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f0.png","sheet_x":37,"sheet_y":10,"short_name":"flag-pk","short_names":["flag-pk"],"text":null,"texts":null,"category":"Flags","sort_order":168,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PL","unified":"1F1F5-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f1.png","sheet_x":37,"sheet_y":11,"short_name":"flag-pl","short_names":["flag-pl"],"text":null,"texts":null,"category":"Flags","sort_order":177,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PM","unified":"1F1F5-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f2.png","sheet_x":37,"sheet_y":12,"short_name":"flag-pm","short_names":["flag-pm"],"text":null,"texts":null,"category":"Flags","sort_order":189,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PN","unified":"1F1F5-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f3.png","sheet_x":37,"sheet_y":13,"short_name":"flag-pn","short_names":["flag-pn"],"text":null,"texts":null,"category":"Flags","sort_order":176,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PR","unified":"1F1F5-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f7.png","sheet_x":37,"sheet_y":14,"short_name":"flag-pr","short_names":["flag-pr"],"text":null,"texts":null,"category":"Flags","sort_order":179,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PS","unified":"1F1F5-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f8.png","sheet_x":37,"sheet_y":15,"short_name":"flag-ps","short_names":["flag-ps"],"text":null,"texts":null,"category":"Flags","sort_order":170,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PT","unified":"1F1F5-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1f9.png","sheet_x":37,"sheet_y":16,"short_name":"flag-pt","short_names":["flag-pt"],"text":null,"texts":null,"category":"Flags","sort_order":178,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PW","unified":"1F1F5-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1fc.png","sheet_x":37,"sheet_y":17,"short_name":"flag-pw","short_names":["flag-pw"],"text":null,"texts":null,"category":"Flags","sort_order":169,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS PY","unified":"1F1F5-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f5-1f1fe.png","sheet_x":37,"sheet_y":18,"short_name":"flag-py","short_names":["flag-py"],"text":null,"texts":null,"category":"Flags","sort_order":173,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS QA","unified":"1F1F6-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f6-1f1e6.png","sheet_x":37,"sheet_y":19,"short_name":"flag-qa","short_names":["flag-qa"],"text":null,"texts":null,"category":"Flags","sort_order":180,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS RE","unified":"1F1F7-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f7-1f1ea.png","sheet_x":37,"sheet_y":20,"short_name":"flag-re","short_names":["flag-re"],"text":null,"texts":null,"category":"Flags","sort_order":181,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS RO","unified":"1F1F7-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f7-1f1f4.png","sheet_x":37,"sheet_y":21,"short_name":"flag-ro","short_names":["flag-ro"],"text":null,"texts":null,"category":"Flags","sort_order":182,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS RS","unified":"1F1F7-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f7-1f1f8.png","sheet_x":37,"sheet_y":22,"short_name":"flag-rs","short_names":["flag-rs"],"text":null,"texts":null,"category":"Flags","sort_order":196,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS RU","unified":"1F1F7-1F1FA","variations":[],"docomo":null,"au":"E5D6","softbank":"E512","google":"FE4EC","image":"1f1f7-1f1fa.png","sheet_x":37,"sheet_y":23,"short_name":"flag-ru","short_names":["flag-ru","ru"],"text":null,"texts":null,"category":"Flags","sort_order":183,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS RW","unified":"1F1F7-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f7-1f1fc.png","sheet_x":37,"sheet_y":24,"short_name":"flag-rw","short_names":["flag-rw"],"text":null,"texts":null,"category":"Flags","sort_order":184,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SA","unified":"1F1F8-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1e6.png","sheet_x":37,"sheet_y":25,"short_name":"flag-sa","short_names":["flag-sa"],"text":null,"texts":null,"category":"Flags","sort_order":194,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SB","unified":"1F1F8-1F1E7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1e7.png","sheet_x":37,"sheet_y":26,"short_name":"flag-sb","short_names":["flag-sb"],"text":null,"texts":null,"category":"Flags","sort_order":203,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SC","unified":"1F1F8-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1e8.png","sheet_x":37,"sheet_y":27,"short_name":"flag-sc","short_names":["flag-sc"],"text":null,"texts":null,"category":"Flags","sort_order":197,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SD","unified":"1F1F8-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1e9.png","sheet_x":37,"sheet_y":28,"short_name":"flag-sd","short_names":["flag-sd"],"text":null,"texts":null,"category":"Flags","sort_order":211,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SE","unified":"1F1F8-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ea.png","sheet_x":37,"sheet_y":29,"short_name":"flag-se","short_names":["flag-se"],"text":null,"texts":null,"category":"Flags","sort_order":214,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SG","unified":"1F1F8-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ec.png","sheet_x":37,"sheet_y":30,"short_name":"flag-sg","short_names":["flag-sg"],"text":null,"texts":null,"category":"Flags","sort_order":199,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SH","unified":"1F1F8-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ed.png","sheet_x":37,"sheet_y":31,"short_name":"flag-sh","short_names":["flag-sh"],"text":null,"texts":null,"category":"Flags","sort_order":186,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SI","unified":"1F1F8-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ee.png","sheet_x":37,"sheet_y":32,"short_name":"flag-si","short_names":["flag-si"],"text":null,"texts":null,"category":"Flags","sort_order":202,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SJ","unified":"1F1F8-1F1EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ef.png","sheet_x":37,"sheet_y":33,"short_name":"flag-sj","short_names":["flag-sj"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SK","unified":"1F1F8-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f0.png","sheet_x":37,"sheet_y":34,"short_name":"flag-sk","short_names":["flag-sk"],"text":null,"texts":null,"category":"Flags","sort_order":201,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SL","unified":"1F1F8-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f1.png","sheet_x":37,"sheet_y":35,"short_name":"flag-sl","short_names":["flag-sl"],"text":null,"texts":null,"category":"Flags","sort_order":198,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SM","unified":"1F1F8-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f2.png","sheet_x":37,"sheet_y":36,"short_name":"flag-sm","short_names":["flag-sm"],"text":null,"texts":null,"category":"Flags","sort_order":192,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SN","unified":"1F1F8-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f3.png","sheet_x":37,"sheet_y":37,"short_name":"flag-sn","short_names":["flag-sn"],"text":null,"texts":null,"category":"Flags","sort_order":195,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SO","unified":"1F1F8-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f4.png","sheet_x":37,"sheet_y":38,"short_name":"flag-so","short_names":["flag-so"],"text":null,"texts":null,"category":"Flags","sort_order":204,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SR","unified":"1F1F8-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f7.png","sheet_x":37,"sheet_y":39,"short_name":"flag-sr","short_names":["flag-sr"],"text":null,"texts":null,"category":"Flags","sort_order":212,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SS","unified":"1F1F8-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f8.png","sheet_x":37,"sheet_y":40,"short_name":"flag-ss","short_names":["flag-ss"],"text":null,"texts":null,"category":"Flags","sort_order":208,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ST","unified":"1F1F8-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1f9.png","sheet_x":38,"sheet_y":0,"short_name":"flag-st","short_names":["flag-st"],"text":null,"texts":null,"category":"Flags","sort_order":193,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SV","unified":"1F1F8-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1fb.png","sheet_x":38,"sheet_y":1,"short_name":"flag-sv","short_names":["flag-sv"],"text":null,"texts":null,"category":"Flags","sort_order":67,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SX","unified":"1F1F8-1F1FD","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1fd.png","sheet_x":38,"sheet_y":2,"short_name":"flag-sx","short_names":["flag-sx"],"text":null,"texts":null,"category":"Flags","sort_order":200,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SY","unified":"1F1F8-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1fe.png","sheet_x":38,"sheet_y":3,"short_name":"flag-sy","short_names":["flag-sy"],"text":null,"texts":null,"category":"Flags","sort_order":216,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS SZ","unified":"1F1F8-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f8-1f1ff.png","sheet_x":38,"sheet_y":4,"short_name":"flag-sz","short_names":["flag-sz"],"text":null,"texts":null,"category":"Flags","sort_order":213,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TA","unified":"1F1F9-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1e6.png","sheet_x":38,"sheet_y":5,"short_name":"flag-ta","short_names":["flag-ta"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TC","unified":"1F1F9-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1e8.png","sheet_x":38,"sheet_y":6,"short_name":"flag-tc","short_names":["flag-tc"],"text":null,"texts":null,"category":"Flags","sort_order":229,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TD","unified":"1F1F9-1F1E9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1e9.png","sheet_x":38,"sheet_y":7,"short_name":"flag-td","short_names":["flag-td"],"text":null,"texts":null,"category":"Flags","sort_order":45,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TF","unified":"1F1F9-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1eb.png","sheet_x":38,"sheet_y":8,"short_name":"flag-tf","short_names":["flag-tf"],"text":null,"texts":null,"category":"Flags","sort_order":80,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TG","unified":"1F1F9-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1ec.png","sheet_x":38,"sheet_y":9,"short_name":"flag-tg","short_names":["flag-tg"],"text":null,"texts":null,"category":"Flags","sort_order":222,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TH","unified":"1F1F9-1F1ED","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1ed.png","sheet_x":38,"sheet_y":10,"short_name":"flag-th","short_names":["flag-th"],"text":null,"texts":null,"category":"Flags","sort_order":220,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TJ","unified":"1F1F9-1F1EF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1ef.png","sheet_x":38,"sheet_y":11,"short_name":"flag-tj","short_names":["flag-tj"],"text":null,"texts":null,"category":"Flags","sort_order":218,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TK","unified":"1F1F9-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f0.png","sheet_x":38,"sheet_y":12,"short_name":"flag-tk","short_names":["flag-tk"],"text":null,"texts":null,"category":"Flags","sort_order":223,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TL","unified":"1F1F9-1F1F1","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f1.png","sheet_x":38,"sheet_y":13,"short_name":"flag-tl","short_names":["flag-tl"],"text":null,"texts":null,"category":"Flags","sort_order":221,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TM","unified":"1F1F9-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f2.png","sheet_x":38,"sheet_y":14,"short_name":"flag-tm","short_names":["flag-tm"],"text":null,"texts":null,"category":"Flags","sort_order":228,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TN","unified":"1F1F9-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f3.png","sheet_x":38,"sheet_y":15,"short_name":"flag-tn","short_names":["flag-tn"],"text":null,"texts":null,"category":"Flags","sort_order":226,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TO","unified":"1F1F9-1F1F4","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f4.png","sheet_x":38,"sheet_y":16,"short_name":"flag-to","short_names":["flag-to"],"text":null,"texts":null,"category":"Flags","sort_order":224,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TR","unified":"1F1F9-1F1F7","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f7.png","sheet_x":38,"sheet_y":17,"short_name":"flag-tr","short_names":["flag-tr"],"text":null,"texts":null,"category":"Flags","sort_order":227,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TT","unified":"1F1F9-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1f9.png","sheet_x":38,"sheet_y":18,"short_name":"flag-tt","short_names":["flag-tt"],"text":null,"texts":null,"category":"Flags","sort_order":225,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TV","unified":"1F1F9-1F1FB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1fb.png","sheet_x":38,"sheet_y":19,"short_name":"flag-tv","short_names":["flag-tv"],"text":null,"texts":null,"category":"Flags","sort_order":230,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TW","unified":"1F1F9-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1fc.png","sheet_x":38,"sheet_y":20,"short_name":"flag-tw","short_names":["flag-tw"],"text":null,"texts":null,"category":"Flags","sort_order":217,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS TZ","unified":"1F1F9-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1f9-1f1ff.png","sheet_x":38,"sheet_y":21,"short_name":"flag-tz","short_names":["flag-tz"],"text":null,"texts":null,"category":"Flags","sort_order":219,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS UA","unified":"1F1FA-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fa-1f1e6.png","sheet_x":38,"sheet_y":22,"short_name":"flag-ua","short_names":["flag-ua"],"text":null,"texts":null,"category":"Flags","sort_order":232,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS UG","unified":"1F1FA-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fa-1f1ec.png","sheet_x":38,"sheet_y":23,"short_name":"flag-ug","short_names":["flag-ug"],"text":null,"texts":null,"category":"Flags","sort_order":231,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS UM","unified":"1F1FA-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fa-1f1f2.png","sheet_x":38,"sheet_y":24,"short_name":"flag-um","short_names":["flag-um"],"text":null,"texts":null,"category":null,"sort_order":null,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS US","unified":"1F1FA-1F1F8","variations":[],"docomo":null,"au":"E573","softbank":"E50C","google":"FE4E6","image":"1f1fa-1f1f8.png","sheet_x":38,"sheet_y":25,"short_name":"flag-us","short_names":["flag-us","us"],"text":null,"texts":null,"category":"Flags","sort_order":235,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS UY","unified":"1F1FA-1F1FE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fa-1f1fe.png","sheet_x":38,"sheet_y":26,"short_name":"flag-uy","short_names":["flag-uy"],"text":null,"texts":null,"category":"Flags","sort_order":237,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS UZ","unified":"1F1FA-1F1FF","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fa-1f1ff.png","sheet_x":38,"sheet_y":27,"short_name":"flag-uz","short_names":["flag-uz"],"text":null,"texts":null,"category":"Flags","sort_order":238,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VA","unified":"1F1FB-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1e6.png","sheet_x":38,"sheet_y":28,"short_name":"flag-va","short_names":["flag-va"],"text":null,"texts":null,"category":"Flags","sort_order":240,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VC","unified":"1F1FB-1F1E8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1e8.png","sheet_x":38,"sheet_y":29,"short_name":"flag-vc","short_names":["flag-vc"],"text":null,"texts":null,"category":"Flags","sort_order":190,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VE","unified":"1F1FB-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1ea.png","sheet_x":38,"sheet_y":30,"short_name":"flag-ve","short_names":["flag-ve"],"text":null,"texts":null,"category":"Flags","sort_order":241,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VG","unified":"1F1FB-1F1EC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1ec.png","sheet_x":38,"sheet_y":31,"short_name":"flag-vg","short_names":["flag-vg"],"text":null,"texts":null,"category":"Flags","sort_order":33,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VI","unified":"1F1FB-1F1EE","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1ee.png","sheet_x":38,"sheet_y":32,"short_name":"flag-vi","short_names":["flag-vi"],"text":null,"texts":null,"category":"Flags","sort_order":236,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VN","unified":"1F1FB-1F1F3","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1f3.png","sheet_x":38,"sheet_y":33,"short_name":"flag-vn","short_names":["flag-vn"],"text":null,"texts":null,"category":"Flags","sort_order":242,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS VU","unified":"1F1FB-1F1FA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fb-1f1fa.png","sheet_x":38,"sheet_y":34,"short_name":"flag-vu","short_names":["flag-vu"],"text":null,"texts":null,"category":"Flags","sort_order":239,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS WF","unified":"1F1FC-1F1EB","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fc-1f1eb.png","sheet_x":38,"sheet_y":35,"short_name":"flag-wf","short_names":["flag-wf"],"text":null,"texts":null,"category":"Flags","sort_order":243,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS WS","unified":"1F1FC-1F1F8","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fc-1f1f8.png","sheet_x":38,"sheet_y":36,"short_name":"flag-ws","short_names":["flag-ws"],"text":null,"texts":null,"category":"Flags","sort_order":191,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS XK","unified":"1F1FD-1F1F0","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fd-1f1f0.png","sheet_x":38,"sheet_y":37,"short_name":"flag-xk","short_names":["flag-xk"],"text":null,"texts":null,"category":"Flags","sort_order":118,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS YE","unified":"1F1FE-1F1EA","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fe-1f1ea.png","sheet_x":38,"sheet_y":38,"short_name":"flag-ye","short_names":["flag-ye"],"text":null,"texts":null,"category":"Flags","sort_order":245,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS YT","unified":"1F1FE-1F1F9","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1fe-1f1f9.png","sheet_x":38,"sheet_y":39,"short_name":"flag-yt","short_names":["flag-yt"],"text":null,"texts":null,"category":"Flags","sort_order":142,"has_img_apple":true,"has_img_google":false,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ZA","unified":"1F1FF-1F1E6","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ff-1f1e6.png","sheet_x":38,"sheet_y":40,"short_name":"flag-za","short_names":["flag-za"],"text":null,"texts":null,"category":"Flags","sort_order":205,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ZM","unified":"1F1FF-1F1F2","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ff-1f1f2.png","sheet_x":39,"sheet_y":0,"short_name":"flag-zm","short_names":["flag-zm"],"text":null,"texts":null,"category":"Flags","sort_order":246,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":"REGIONAL INDICATOR SYMBOL LETTERS ZW","unified":"1F1FF-1F1FC","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f1ff-1f1fc.png","sheet_x":39,"sheet_y":1,"short_name":"flag-zw","short_names":["flag-zw"],"text":null,"texts":null,"category":"Flags","sort_order":247,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F468-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f468-200d-1f466.png","sheet_x":39,"sheet_y":2,"short_name":"man-man-boy","short_names":["man-man-boy"],"text":null,"texts":null,"category":"People","sort_order":171,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F468-200D-1F466-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f468-200d-1f466-200d-1f466.png","sheet_x":39,"sheet_y":3,"short_name":"man-man-boy-boy","short_names":["man-man-boy-boy"],"text":null,"texts":null,"category":"People","sort_order":174,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F468-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f468-200d-1f467.png","sheet_x":39,"sheet_y":4,"short_name":"man-man-girl","short_names":["man-man-girl"],"text":null,"texts":null,"category":"People","sort_order":172,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F468-200D-1F467-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f468-200d-1f467-200d-1f466.png","sheet_x":39,"sheet_y":5,"short_name":"man-man-girl-boy","short_names":["man-man-girl-boy"],"text":null,"texts":null,"category":"People","sort_order":173,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F468-200D-1F467-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f468-200d-1f467-200d-1f467.png","sheet_x":39,"sheet_y":6,"short_name":"man-man-girl-girl","short_names":["man-man-girl-girl"],"text":null,"texts":null,"category":"People","sort_order":175,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F469-200D-1F466-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f469-200d-1f466-200d-1f466.png","sheet_x":39,"sheet_y":7,"short_name":"man-woman-boy-boy","short_names":["man-woman-boy-boy"],"text":null,"texts":null,"category":"People","sort_order":164,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F469-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f469-200d-1f467.png","sheet_x":39,"sheet_y":8,"short_name":"man-woman-girl","short_names":["man-woman-girl"],"text":null,"texts":null,"category":"People","sort_order":162,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F469-200D-1F467-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f469-200d-1f467-200d-1f466.png","sheet_x":39,"sheet_y":9,"short_name":"man-woman-girl-boy","short_names":["man-woman-girl-boy"],"text":null,"texts":null,"category":"People","sort_order":163,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-1F469-200D-1F467-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-1f469-200d-1f467-200d-1f467.png","sheet_x":39,"sheet_y":10,"short_name":"man-woman-girl-girl","short_names":["man-woman-girl-girl"],"text":null,"texts":null,"category":"People","sort_order":165,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F468-200D-2764-FE0F-200D-1F468","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-2764-fe0f-200d-1f468.png","sheet_x":39,"sheet_y":11,"short_name":"man-heart-man","short_names":["man-heart-man"],"text":null,"texts":null,"category":"People","sort_order":157,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":false},{"name":null,"unified":"1F468-200D-2764-FE0F-200D-1F48B-200D-1F468","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png","sheet_x":39,"sheet_y":12,"short_name":"man-kiss-man","short_names":["man-kiss-man"],"text":null,"texts":null,"category":"People","sort_order":160,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":false},{"name":null,"unified":"1F469-200D-1F469-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-1f469-200d-1f466.png","sheet_x":39,"sheet_y":13,"short_name":"woman-woman-boy","short_names":["woman-woman-boy"],"text":null,"texts":null,"category":"People","sort_order":166,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F469-200D-1F469-200D-1F466-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-1f469-200d-1f466-200d-1f466.png","sheet_x":39,"sheet_y":14,"short_name":"woman-woman-boy-boy","short_names":["woman-woman-boy-boy"],"text":null,"texts":null,"category":"People","sort_order":169,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F469-200D-1F469-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-1f469-200d-1f467.png","sheet_x":39,"sheet_y":15,"short_name":"woman-woman-girl","short_names":["woman-woman-girl"],"text":null,"texts":null,"category":"People","sort_order":167,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F469-200D-1F469-200D-1F467-200D-1F466","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-1f469-200d-1f467-200d-1f466.png","sheet_x":39,"sheet_y":16,"short_name":"woman-woman-girl-boy","short_names":["woman-woman-girl-boy"],"text":null,"texts":null,"category":"People","sort_order":168,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F469-200D-1F469-200D-1F467-200D-1F467","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-1f469-200d-1f467-200d-1f467.png","sheet_x":39,"sheet_y":17,"short_name":"woman-woman-girl-girl","short_names":["woman-woman-girl-girl"],"text":null,"texts":null,"category":"People","sort_order":170,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true},{"name":null,"unified":"1F469-200D-2764-FE0F-200D-1F469","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-2764-fe0f-200d-1f469.png","sheet_x":39,"sheet_y":18,"short_name":"woman-heart-woman","short_names":["woman-heart-woman"],"text":null,"texts":null,"category":"People","sort_order":156,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":false},{"name":null,"unified":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F469","variations":[],"docomo":null,"au":null,"softbank":null,"google":null,"image":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png","sheet_x":39,"sheet_y":19,"short_name":"woman-kiss-woman","short_names":["woman-kiss-woman"],"text":null,"texts":null,"category":"People","sort_order":159,"has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":false}]} ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-message-extension.jsx ================================================ /* eslint no-cond-assign:0 */ import {MessageViewExtension, RegExpUtils} from 'nylas-exports'; import emoji from 'node-emoji'; import EmojiStore from './emoji-store'; function makeIntoEmojiTag(nodeArg, emojiName) { const node = nodeArg; node.src = EmojiStore.getImagePath(emojiName); node.className = `emoji ${emojiName}`; node.width = 14; node.height = 14; node.style = ''; node.style.marginTop = '-5px'; } class EmojiMessageExtension extends MessageViewExtension { static renderedMessageBodyIntoDocument({document}) { const emojiRegex = RegExpUtils.emojiRegex(); // Look for emoji in the content of text nodes const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); while (treeWalker.nextNode()) { emojiRegex.lastIndex = 0; const node = treeWalker.currentNode; let match = null; while (match = emojiRegex.exec(node.textContent)) { const matchEmojiName = emoji.which(match[0]); if (matchEmojiName) { const matchNode = (match.index === 0) ? node : node.splitText(match.index); matchNode.splitText(match[0].length); const imageNode = document.createElement('img'); makeIntoEmojiTag(imageNode, matchEmojiName); matchNode.parentNode.replaceChild(imageNode, matchNode); } } } } } export default EmojiMessageExtension; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-picker.jsx ================================================ import {React, ReactDOM} from 'nylas-exports'; import emoji from 'node-emoji'; import EmojiStore from './emoji-store'; import EmojiActions from './emoji-actions'; class EmojiPicker extends React.Component { static displayName = "EmojiPicker"; static propTypes = { emojiOptions: React.PropTypes.array, selectedEmoji: React.PropTypes.string, }; constructor(props) { super(props); this.state = {}; } componentDidUpdate() { const selectedButton = ReactDOM.findDOMNode(this).querySelector(".emoji-option"); if (selectedButton) { selectedButton.scrollIntoViewIfNeeded(); } } onMouseDown(emojiName) { EmojiActions.selectEmoji({emojiName, replaceSelection: true}); } render() { const emojiButtons = []; let emojiIndex = this.props.emojiOptions.indexOf(this.props.selectedEmoji); if (emojiIndex === -1) emojiIndex = 0; if (this.props.emojiOptions) { this.props.emojiOptions.forEach((emojiOption, i) => { const emojiClass = emojiIndex === i ? "btn btn-icon emoji-option" : "btn btn-icon"; let emojiChar = emoji.get(emojiOption); emojiChar = ( {emojiOption} ); emojiButtons.push( ); emojiButtons.push(
); }); } return (
{emojiButtons}
); } } export default EmojiPicker; ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/emoji-store.jsx ================================================ /* eslint global-require: "off" */ import NylasStore from 'nylas-store'; import _ from 'underscore'; import {Rx, DatabaseStore} from 'nylas-exports'; import EmojiActions from './emoji-actions'; const EmojiJSONBlobKey = 'emoji'; let emojiData; class EmojiStore extends NylasStore { constructor(props) { super(props); this._emoji = []; } activate = () => { const query = DatabaseStore.findJSONBlob(EmojiJSONBlobKey); this._subscription = Rx.Observable.fromQuery(query).subscribe((emoji) => { this._emoji = emoji || []; this.trigger(); }); this.listenTo(EmojiActions.useEmoji, this._onUseEmoji); } frequentlyUsedEmoji = () => { const sortedEmoji = this._emoji; sortedEmoji.sort((a, b) => { if (a.frequency < b.frequency) return 1; return (b.frequency < a.frequency) ? -1 : 0; }); const sortedEmojiNames = []; for (const emoji of sortedEmoji) { sortedEmojiNames.push(emoji.emojiName); } if (sortedEmojiNames.length > 32) { return sortedEmojiNames.slice(0, 32); } return sortedEmojiNames; } getImagePath(emojiName) { emojiData = emojiData || require('./emoji-data').emojiData for (const emoji of emojiData) { if (emoji.short_names.indexOf(emojiName) !== -1) { if (process.platform === "darwin") { return `images/composer-emoji/apple/${emoji.image}`; } return `images/composer-emoji/twitter/${emoji.image}`; } } return '' } _onUseEmoji = (emoji) => { const savedEmoji = _.find(this._emoji, (curEmoji) => { return curEmoji.emojiChar === emoji.emojiChar; }); if (savedEmoji) { for (const key of Object.keys(emoji)) { savedEmoji[key] = emoji[key]; } savedEmoji.frequency++; } else { _.extend(emoji, {frequency: 1}); this._emoji.push(emoji); } this._saveEmoji(); this.trigger(); } _saveEmoji = () => { DatabaseStore.inTransaction((t) => { return t.persistJSONBlob(EmojiJSONBlobKey, this._emoji); }); } } export default new EmojiStore(); ================================================ FILE: packages/client-app/internal_packages/composer-emoji/lib/main.es6 ================================================ import {ExtensionRegistry, ComponentRegistry} from 'nylas-exports'; import EmojiStore from './emoji-store'; import EmojiComposerExtension from './emoji-composer-extension'; import EmojiMessageExtension from './emoji-message-extension'; import EmojiButton from './emoji-button'; export function activate() { ExtensionRegistry.Composer.register(EmojiComposerExtension); ExtensionRegistry.MessageView.register(EmojiMessageExtension); ComponentRegistry.register(EmojiButton, {role: 'Composer:ActionButton'}); EmojiStore.activate(); } export function deactivate() { ExtensionRegistry.Composer.unregister(EmojiComposerExtension); ExtensionRegistry.MessageView.unregister(EmojiMessageExtension); ComponentRegistry.unregister(EmojiButton); } ================================================ FILE: packages/client-app/internal_packages/composer-emoji/package.json ================================================ { "name": "composer-emoji", "main": "./lib/main", "version": "0.1.0", "repository": { "type": "git", "url": "" }, "engines": { "nylas": "*" }, "isOptional": true, "title": "Emoji Picker", "icon": "./assets/icon.png", "description": "Insert emoji into messages by typing a colon (:) and the emoji name or choosing one from the composer toolbar!", "windowTypes": { "default": true, "composer": true, "thread-popout": true }, "license": "GPL-3.0" } ================================================ FILE: packages/client-app/internal_packages/composer-emoji/spec/emoji-button-popover-spec.jsx ================================================ import React from 'react'; import ReactTestUtils from 'react-addons-test-utils'; import {findDOMNode} from 'react-dom'; import {renderIntoDocument} from '../../../spec/nylas-test-utils'; import Contenteditable from '../../../src/components/contenteditable/contenteditable'; import EmojiButtonPopover from '../lib/emoji-button-popover'; import EmojiComposerExtension from '../lib/emoji-composer-extension'; describe('EmojiButtonPopover', function emojiButtonPopover() { beforeEach(() => { this.position = { x: 20, y: 40, } spyOn(EmojiButtonPopover.prototype, 'calcPosition').andReturn(this.position); spyOn(EmojiComposerExtension, '_onSelectEmoji').andCallThrough(); this.component = renderIntoDocument(); this.canvas = findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(this.component, 'canvas')); this.composer = renderIntoDocument( ); }); describe('when inserting emoji', () => { it('should insert emoji on click', () => { ReactTestUtils.Simulate.mouseDown(this.canvas); expect(EmojiComposerExtension._onSelectEmoji).toHaveBeenCalled(); }); }); describe('when searching for emoji', () => { it('should filter for matches', () => { this.searchNode = findDOMNode(ReactTestUtils.findRenderedDOMComponentWithClass(this.component, 'search')) const event = { target: { value: "heart", }, } ReactTestUtils.Simulate.change(this.searchNode, event); ReactTestUtils.Simulate.mouseDown(this.canvas); expect(EmojiComposerExtension._onSelectEmoji).toHaveBeenCalled(); }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-emoji/spec/emoji-composer-extension-spec.jsx ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-addons-test-utils'; import {renderIntoDocument} from '../../../spec/nylas-test-utils'; import Contenteditable from '../../../src/components/contenteditable/contenteditable'; import EmojiComposerExtension from '../lib/emoji-composer-extension'; describe('EmojiComposerExtension', function emojiComposerExtension() { beforeEach(() => { spyOn(EmojiComposerExtension, 'onContentChanged').andCallThrough() spyOn(EmojiComposerExtension, '_onSelectEmoji').andCallThrough() this.component = renderIntoDocument( ) this.editableNode = ReactDOM.findDOMNode(this.component).querySelector('[contenteditable]'); }) describe('when emoji trigger is typed', () => { beforeEach(() => { this._performEdit = (newHTML) => { this.editableNode.innerHTML = newHTML; const sel = document.getSelection() const textNode = this.editableNode.childNodes[0]; sel.setBaseAndExtent(textNode, textNode.nodeValue.length, textNode, textNode.nodeValue.length); } }) it('should show the emoji picker', () => { this._performEdit('Testing! :h'); waitsFor(() => { return ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, 'emoji-picker').length > 0 }); }) it('should be focused on the first emoji in the list', () => { this._performEdit('Testing! :h'); waitsFor(() => { return ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, 'emoji-option').length > 0 }); runs(() => { expect(ReactDOM.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithClass(this.component, 'emoji-option')).textContent.indexOf(":haircut:") !== -1).toBe(true); }); }) it('should insert an emoji on enter', () => { this._performEdit('Testing! :h'); waitsFor(() => { return ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, 'emoji-picker').length > 0 }); runs(() => { ReactTestUtils.Simulate.keyDown(this.editableNode, {key: "Enter", keyCode: 13, which: 13}); }); waitsFor(() => { return EmojiComposerExtension._onSelectEmoji.calls.length > 0 }) runs(() => { expect(this.editableNode.innerHTML).toContain("emoji haircut") }); }) it('should insert an emoji on click', () => { this._performEdit('Testing! :h'); waitsFor(() => { return ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, 'emoji-picker').length > 0 }); runs(() => { const button = ReactDOM.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithClass(this.component, 'emoji-option')) ReactTestUtils.Simulate.mouseDown(button); expect(EmojiComposerExtension._onSelectEmoji).toHaveBeenCalled() }); waitsFor(() => { return EmojiComposerExtension._onSelectEmoji.calls.length > 0 }) runs(() => { expect(this.editableNode.innerHTML).toContain("emoji haircut") }); }) it('should move to the next emoji on arrow down', () => { this._performEdit('Testing! :h'); waitsFor(() => { return ReactTestUtils.scryRenderedDOMComponentsWithClass(this.component, 'emoji-option').length > 0 }); runs(() => { ReactTestUtils.Simulate.keyDown(this.editableNode, {key: "ArrowDown", keyCode: 40, which: 40}); }); waitsFor(() => { return EmojiComposerExtension.onContentChanged.calls.length > 1 }); runs(() => { expect(ReactDOM.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithClass(this.component, 'emoji-option')).textContent.indexOf(":hamburger:") !== -1).toBe(true); }); }) }) }) ================================================ FILE: packages/client-app/internal_packages/composer-emoji/stylesheets/composer-emoji.less ================================================ @import "ui-variables"; .emoji-picker { max-height: 130px !important; margin: 10px; overflow: auto; .btn.btn-icon { font-size: 14px !important; padding: 0 0.5em; &:first-child { padding-left: 0.5em !important; } &.emoji-option, &:hover { background-color: @btn-emphasis-bg-color; color: #FFFFFF; border-radius: 5px; } } } .emoji-button-popover { width: 210px; height: 290px; overflow: hidden; .emoji-tabs { display: flex; flex-direction: row; padding: 5px 5px 5px 10px; border-bottom: 1px solid @border-color-primary; transition: box-shadow 0.5s; &.shadow { box-shadow: @standard-shadow; } .emoji-tab { background-color: @gray-light; &.active { background-color: @component-active-color; } } } .emoji-finder-container { height: 232px; .scrollbar-track { background: transparent; border-left: none; width: 10px; } .emoji-search-container { padding: @padding-base-vertical * 1.5 @padding-base-horizontal 0; } } .emoji-name { height: 25px; width: 192px; margin-top: 2px; margin-left: 10px; overflow: hidden; text-overflow: ellipsis; color: @text-color-very-subtle; } } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/listens-to-mail-merge-session.jsx ================================================ /* eslint no-prototype-builtins: 0 */ import React, {Component, PropTypes} from 'react'; import {mailMergeSessionForDraft} from './mail-merge-draft-editing-session' export default function ListensToMailMergeSession(ComposedComponent) { return class extends Component { static displayName = ComposedComponent.displayName static containerRequired = false static propTypes = { session: PropTypes.object, draftClientId: PropTypes.string, ...ComposedComponent.propTypes, } constructor(props) { super(props) this.unlisten = () => {} this.state = { mailMergeSession: mailMergeSessionForDraft(props.draftClientId, props.session), }; } componentDidMount() { const {mailMergeSession} = this.state; if (mailMergeSession) { this.unlisten = mailMergeSession.listen(() => { this.setState({mailMergeSession}) }); } } componentWillUnmount() { this.unlisten(); } focus() { if (this.refs.composed) { this.refs.composed.focus() } } render() { const {mailMergeSession} = this.state; if (!mailMergeSession) { return } const componentProps = { ...this.props, mailMergeSession: mailMergeSession, sessionState: mailMergeSession.state, } if (Component.isPrototypeOf(ComposedComponent)) { componentProps.ref = 'composed' } return ( ) } } } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-body-token.jsx ================================================ import React, {Component, PropTypes} from 'react' import MailMergeToken from './mail-merge-token' import {DragBehaviors} from './mail-merge-constants' import {tokenQuerySelector} from './mail-merge-utils' import ListensToMailMergeSession from './listens-to-mail-merge-session' /** * MailMergeBodyTokens are rendered by the OverlaidComponents component in the * subject and body of the composer. * The OverlaidComponents' state is effectively the state of the contenteditable * inside those fields, * and it decides what to render based on the * anchor (img) tags that are present in the contenteditable. * * Given this setup, we use the lifecycle methods of MailMergeBodyToken to keep * the state of the contenteditable (the tokens actually rendered in the UI), * in sync with our token state for mail merge (tokenDataSource) */ class MailMergeBodyToken extends Component { static displayName = 'MailMergeBodyToken' static propTypes = { className: PropTypes.string, tokenId: PropTypes.string, field: PropTypes.string, colName: PropTypes.string, sessionState: PropTypes.object, mailMergeSession: PropTypes.object, draftClientId: PropTypes.string, colIdx: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), isPreview: PropTypes.bool, } constructor(props) { super(props) this.state = this.getState(props) } componentDidMount() { // When the token gets mounted, it means a mail merge token anchor node was // added to the contenteditable, via drop, paste, or any other means, so we // add it to our mail merge state const {colIdx, field, colName, tokenId, mailMergeSession} = this.props const {tokenDataSource} = mailMergeSession.state const token = tokenDataSource.getToken(field, tokenId) if (!token) { mailMergeSession.linkToDraft({colIdx, field, colName, tokenId}) } } componentWillReceiveProps(nextProps) { this.setState(this.getState(nextProps, this.state.colIdx)) } shouldComponentUpdate(nextProps, nextState) { return ( this.props.isPreview !== nextProps.isPreview || this.state.colIdx !== nextState.colIdx || this.props.sessionState.selection !== nextProps.sessionState.selection || this.props.sessionState.tableDataSource !== nextProps.sessionState.tableDataSource || this.props.sessionState.tokenDataSource !== nextProps.sessionState.tokenDataSource ) } componentDidUpdate() { // A token might be removed by mutations to the contenteditable, in which // case the tokenDataSource's state is updated by componentWillUnmount. // // However, when a token is removed from state via other means, e.g. when a // table column is removed, we also want to make sure that we remove it from the // UI. Since the contenteditable is effectively the source of state for // OverlaidComponents, we imperatively remove the token from contenteditable // if it has been removed from our state. const {field, tokenId, sessionState: {tokenDataSource}} = this.props const token = tokenDataSource.getToken(field, tokenId) if (!token) { const node = document.querySelector(tokenQuerySelector(tokenId)) if (node) { node.parentNode.removeChild(node) } } } componentWillUnmount() { // A token might be removed by any sort of mutations to the contenteditable. // When an the actual anchor node in the contenteditable is removed from // the dom tree, OverlaidComponents will unmount our corresponding token, // so this is where we get to update our tokenDataSource's state const {field, tokenId, mailMergeSession} = this.props mailMergeSession.unlinkFromDraft({field, tokenId}) } getState(props) { // Keep colIdx as state in case the column changes index when importing a // new csv file, thus changing styling const {sessionState: {tokenDataSource}, field, tokenId} = props const nextToken = tokenDataSource.getToken(field, tokenId) if (nextToken) { const {colIdx, colName} = nextToken return {colIdx, colName} } const {colIdx, colName} = props return {colIdx, colName} } render() { const {colIdx, colName} = this.state const {className, draftClientId, sessionState, isPreview} = this.props const {tableDataSource, selection} = sessionState const selectionValue = tableDataSource.cellAt({rowIdx: selection.rowIdx, colIdx}) || "No value selected" if (isPreview) { return {selectionValue} } return ( {selectionValue} ) } } export default ListensToMailMergeSession(MailMergeBodyToken) ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-button.jsx ================================================ import classnames from 'classnames' import React, {PropTypes} from 'react' import {RetinaImg} from 'nylas-component-kit' import ListensToMailMergeSession from './listens-to-mail-merge-session' function MailMergeButton(props) { if (props.draft.replyToMessageId) { return ; } const {mailMergeSession, sessionState} = props const {isWorkspaceOpen} = sessionState const classes = classnames({ "btn": true, "btn-toolbar": true, "btn-enabled": isWorkspaceOpen, "btn-mail-merge": true, }) return ( ) } MailMergeButton.displayName = 'MailMergeButton' MailMergeButton.containerRequired = false MailMergeButton.propTypes = { draft: PropTypes.object, session: PropTypes.object, sessionState: PropTypes.object, draftClientId: PropTypes.string, mailMergeSession: PropTypes.object, } export default ListensToMailMergeSession(MailMergeButton) ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-composer-extension.es6 ================================================ import * as Handlers from './mail-merge-token-dnd-handlers' export const name = 'MailMergeComposerExtension' export { onDragOver, shouldAcceptDrop, } from './mail-merge-token-dnd-handlers' export const onDrop = Handlers.onDrop.bind(null, 'body') ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-constants.es6 ================================================ import plugin from '../package.json' export const PLUGIN_ID = plugin.name; export const PLUGIN_NAME = "Mail Merge" export const DEBUG = false export const MAX_ROWS = 150 export const ParticipantFields = ['to', 'cc', 'bcc'] export const ContenteditableFields = ['subject', 'body'] export const LinkableFields = [...ParticipantFields, ...ContenteditableFields] export const DataTransferTypes = { ColIdx: 'mail-merge:col-idx', ColName: 'mail-merge:col-name', DraftId: 'mail-merge:draft-client-id', DragBehavior: 'mail-merge:drag-behavior', } export const DragBehaviors = { Copy: 'copy', Move: 'move', } export const ActionNames = [ 'addColumn', 'removeLastColumn', 'addRow', 'removeRow', 'updateCell', 'shiftSelection', 'setSelection', 'clearTableData', 'loadTableData', 'toggleWorkspace', 'linkToDraft', 'unlinkFromDraft', ] ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-container.jsx ================================================ import React, {Component, PropTypes} from 'react' import MailMergeWorkspace from './mail-merge-workspace' import ListensToMailMergeSession from './listens-to-mail-merge-session' class MailMergeContainer extends Component { static displayName = 'MailMergeContainer' static containerRequired = false static propTypes = { session: PropTypes.object, sessionState: PropTypes.object, draftClientId: PropTypes.string, mailMergeSession: PropTypes.object, } shouldComponentUpdate(nextProps) { // Make sure we only update if new state has been set // We do not care about our other props return ( this.props.draftClientId !== nextProps.draftClientId || this.props.sessionState !== nextProps.sessionState ) } render() { const {draftClientId, sessionState, mailMergeSession} = this.props return ( ) } } export default ListensToMailMergeSession(MailMergeContainer) ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-draft-editing-session.es6 ================================================ import NylasStore from 'nylas-store' import * as TableStateReducers from './table-state-reducers' import * as TokenStateReducers from './token-state-reducers' import * as SelectionStateReducers from './selection-state-reducers' import * as WorkspaceStateReducers from './workspace-state-reducers' import {ActionNames, PLUGIN_ID, DEBUG} from './mail-merge-constants' const sessions = new Map() function computeNextState({name, args = []}, previousState = {}, reducers = []) { if (reducers.length === 0) { return previousState } return reducers.reduce((state, reducer) => { if (reducer[name]) { const reduced = reducer[name](previousState, ...args) return {...state, ...reduced} } return state }, previousState) } /** * MailMergeDraftEditingSession instances hold the entire state for the Mail Merge * plugin for a given draft, as a single state tree. Sessions trigger when any changes * on the state tree occur. * * Mail Merge state for a draft can be modified by dispatching actions on a session instance. * Available actions are defined by `MailMergeConstants.ActionNames`. * Actions are dispatched by calling the action on a session as a method: * ``` * session.addColumn() * ``` * * Internally, the session acts as a Proxy which forwards action calls into any * registered reducers, and merges the resulting state from calling the action * on each reducer to compute the new state tree. Registered reducers are * currently hardcoded in this class. * * A session instance also acts as a proxy for the corresponding `DraftEditingSession`, * instance, and forwards to it any changes that need to be persisted on the draft object * * @class MailMergeDraftEditingSession */ export class MailMergeDraftEditingSession extends NylasStore { constructor(session, reducers) { super() this._session = session this._reducers = reducers || [ TableStateReducers, TokenStateReducers, SelectionStateReducers, WorkspaceStateReducers, ] this._state = {} this.initializeState() this.initializeActionHandlers() } get state() { return this._state } draft() { return this._session.draft() } draftSession() { return this._session } initializeState(draft = this._session.draft()) { const savedMetadata = draft.metadataForPluginId(PLUGIN_ID) const shouldLoadSavedData = ( savedMetadata && savedMetadata.tableDataSource && savedMetadata.tokenDataSource ) const action = {name: 'initialState'} if (shouldLoadSavedData) { const loadedState = this.dispatch({name: 'fromJSON'}, savedMetadata) this._state = this.dispatch(action, loadedState) } else { this._state = this.dispatch(action) } } initializeActionHandlers() { ActionNames.forEach((actionName) => { // TODO ES6 Proxies would be nice here this[actionName] = this.actionHandler(actionName).bind(this) }) } dispatch(action, prevState = this._state) { const nextState = computeNextState(action, prevState, this._reducers) if (DEBUG && action.debug !== false) { console.log('--> action', action.name) console.dir(action) console.log('--> prev state') console.dir(prevState) console.log('--> new state') console.dir(nextState) } return nextState } actionHandler(actionName) { return (...args) => { this._state = this.dispatch({name: actionName, args}) // Defer calling `saveToSession` to make sure our state changes are triggered // before the draft changes this.trigger() setImmediate(this.saveToDraftSession) } } saveToDraftSession = () => { // TODO // - What should we save in metadata? // - The entire table data? // - A reference to a statically hosted file? // - Attach csv as a file to the "base" or "template" draft? const {tokenDataSource, tableDataSource} = this._state const draftChanges = this.dispatch({name: 'toDraftChanges', args: [this._state], debug: false}, this.draft()) const serializedState = this.dispatch({name: 'toJSON', debug: false}, {tokenDataSource, tableDataSource}) this._session.changes.add(draftChanges) this._session.changes.addPluginMetadata(PLUGIN_ID, serializedState) } } export function mailMergeSessionForDraft(draftId, draftSession) { if (sessions.has(draftId)) { return sessions.get(draftId) } if (!draftSession) { return null } const sess = new MailMergeDraftEditingSession(draftSession) sessions.set(draftId, sess) return sess } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-header-input.jsx ================================================ import React, {Component, PropTypes} from 'react' import {pickHTMLProps} from 'pick-react-known-prop' import MailMergeToken from './mail-merge-token' function getInputSize(value) { return ((value || '').length || 1) + 1 } class MailMergeHeaderInput extends Component { static propTypes = { draftClientId: PropTypes.string, colIdx: PropTypes.any, tableDataSource: PropTypes.object, defaultValue: PropTypes.string, onBlur: PropTypes.func, } constructor(props) { super(props) this.state = {inputSize: getInputSize(props.defaultValue)} } componentWillReceiveProps(nextProps) { this.setState({inputSize: getInputSize(nextProps.defaultValue)}) } onInputBlur = (event) => { const {target: {value}} = event this.setState({inputSize: getInputSize(value)}) // Can't override the original onBlur handler this.props.onBlur(event) } onInputChange = (event) => { const {target: {value}} = event this.setState({inputSize: getInputSize(value)}) } render() { const {inputSize} = this.state const {draftClientId, tableDataSource, colIdx, ...props} = this.props const colName = tableDataSource.colAt(colIdx) return (
) } } export default MailMergeHeaderInput ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-participants-text-field.jsx ================================================ import React, {Component, PropTypes} from 'react'; import classnames from 'classnames' import {DropZone, TokenizingTextField} from 'nylas-component-kit' import MailMergeToken from './mail-merge-token' import {DataTransferTypes} from './mail-merge-constants' import ListensToMailMergeSession from './listens-to-mail-merge-session' function MailMergeParticipantToken(props) { const {token: {tableDataSource, rowIdx, colIdx, colName}} = props const selectionValue = tableDataSource.cellAt({rowIdx, colIdx}) || 'No value selected' return ( {selectionValue} ) } MailMergeParticipantToken.propTypes = { token: PropTypes.shape({ colIdx: PropTypes.any, rowIdx: PropTypes.any, tableDataSource: PropTypes.object, }), } class MailMergeParticipantsTextField extends Component { static displayName = 'MailMergeParticipantsTextField' static containerRequired = false static propTypes = { onAdd: PropTypes.func, onRemove: PropTypes.func, field: PropTypes.string, session: PropTypes.object, className: PropTypes.string, sessionState: PropTypes.object, draftClientId: PropTypes.string, mailMergeSession: PropTypes.object, } static defaultProps = { className: '', } constructor(props) { super(props) this._tokenWasMovedBetweenFields = false } // This is called by the TokenizingTextField when a token is dragged and dropped // between fields onAddToken = (...args) => { const tokenToAdd = args[0][0] if (args.length > 1 || !tokenToAdd) { return } const {mailMergeSession} = this.props const {colIdx, colName, tokenId, field} = tokenToAdd // Remove from previous field mailMergeSession.unlinkFromDraft({field, tokenId}) // Add to our current field mailMergeSession.linkToDraft({colIdx, colName, field: this.props.field}) this._tokenWasMovedBetweenFields = true } onRemoveToken = ([tokenToDelete]) => { const {field, mailMergeSession} = this.props const {tokenId} = tokenToDelete mailMergeSession.unlinkFromDraft({field, tokenId}) } onDrop = (event) => { if (this._tokenWasMovedBetweenFields) { // Ignore drop if we already added the token this._tokenWasMovedBetweenFields = false return } const {dataTransfer} = event const {field, mailMergeSession} = this.props const colIdx = dataTransfer.getData(DataTransferTypes.ColIdx) const colName = dataTransfer.getData(DataTransferTypes.ColName) mailMergeSession.linkToDraft({colIdx, colName, field}) } focus() { this.refs.textField.focus() } shouldAcceptDrop = (event) => { const {dataTransfer} = event return !!dataTransfer.getData(DataTransferTypes.ColIdx) } render() { const {field, className, sessionState} = this.props const {isWorkspaceOpen, tableDataSource, selection, tokenDataSource} = sessionState if (!isWorkspaceOpen) { return } const classes = classnames({ 'mail-merge-participants-text-field': true, [className]: true, }) const tokens = ( tokenDataSource.tokensForField(field) .map((token) => ({...token, tableDataSource, rowIdx: selection.rowIdx})) ) return ( token.tokenId} tokenRenderer={MailMergeParticipantToken} tokenIsValid={() => true} tokenClassNames={(token) => `token-color-${token.colIdx % 5}`} onRequestCompletions={() => []} completionNode={() => } onAdd={this.onAddToken} onRemove={this.onRemoveToken} onTokenAction={false} /> ) } } export default ListensToMailMergeSession(MailMergeParticipantsTextField) ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-send-button.jsx ================================================ import {remote} from 'electron' import React, {Component, PropTypes} from 'react' import {RetinaImg} from 'nylas-component-kit' import {sendMailMerge} from './mail-merge-utils' import ListensToMailMergeSession from './listens-to-mail-merge-session' class MailMergeSendButton extends Component { static displayName = 'MailMergeSendButton' static containerRequired = false static propTypes = { draft: PropTypes.object, session: PropTypes.object, sessionState: PropTypes.object, isValidDraft: PropTypes.func, fallback: PropTypes.func, } constructor(props) { super(props) this.state = { sending: false, } } onClick = () => { const {sending} = this.state if (sending) { return } const {draft, isValidDraft} = this.props if (draft.to.length === 0) { const dialog = remote.dialog; dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', buttons: ['Edit Message', 'Cancel'], message: 'Cannot Send', detail: "Before sending, you need to drag the header cell of the column of emails to the To field in Recipients", }); } else { if (isValidDraft()) { this.setState({sending: true}) try { sendMailMerge(draft.clientId) } catch (e) { this.setState({sending: false}) NylasEnv.showErrorDialog(e.message) } } } } primarySend() { // Primary click is called when mod+enter is pressed. // If mail merge is not open, we should revert to default behavior const {isWorkspaceOpen} = this.props.sessionState if (!isWorkspaceOpen && this.refs.fallbackButton) { this.refs.fallbackButton.primarySend() } else { this.onClick() } } render() { const {sending} = this.state const {isWorkspaceOpen, tableDataSource} = this.props.sessionState if (!isWorkspaceOpen) { const Fallback = this.props.fallback return } const count = tableDataSource.rows().length const action = sending ? 'Sending' : 'Send' const sendLabel = count > 1 ? `${action} ${count} messages` : `${action} ${count} message`; let classes = "btn btn-toolbar btn-normal btn-emphasis btn-text btn-send" if (sending) { classes += " btn-disabled" } return ( ); } } // TODO this is a hack so that the mail merge send button can still expose // the `primarySend` method required by the ComposerView. Ideally, this // decorator mechanism should expose whatever instance methods are exposed // by the component its wrapping. // However, I think the better fix will happen when mail merge lives in its // own window and doesn't need to override the Composer's send button, which // is already a bit of a hack. const EnhancedMailMergeSendButton = ListensToMailMergeSession(MailMergeSendButton) Object.assign(EnhancedMailMergeSendButton.prototype, { primarySend() { if (this.refs.composed) { this.refs.composed.primarySend() } }, }) export default EnhancedMailMergeSendButton ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-subject-text-field.jsx ================================================ /* eslint react/no-danger: 0 */ import React, {Component, PropTypes} from 'react' import {findDOMNode} from 'react-dom' import {EditorAPI} from 'nylas-exports' import {OverlaidComponents, DropZone} from 'nylas-component-kit' import ListensToMailMergeSession from './listens-to-mail-merge-session' import * as Handlers from './mail-merge-token-dnd-handlers' class MailMergeSubjectTextField extends Component { static displayName = 'MailMergeSubjectTextField' static containerRequired = false static propTypes = { value: PropTypes.string, fallback: PropTypes.func, draft: PropTypes.object, session: PropTypes.object, sessionState: PropTypes.object, draftClientId: PropTypes.string, onSubjectChange: PropTypes.func.isRequired, } componentDidMount() { const {isWorkspaceOpen} = this.props.sessionState this.savedSelection = null if (isWorkspaceOpen) { this.editor = new EditorAPI(findDOMNode(this.refs.contenteditable)) } } shouldComponentUpdate(nextProps) { return ( this.props.draftClientId !== nextProps.draftClientId || this.props.value !== nextProps.value || this.props.sessionState.isWorkspaceOpen !== nextProps.sessionState.isWorkspaceOpen ) } componentDidUpdate() { const {isWorkspaceOpen} = this.props.sessionState if (isWorkspaceOpen) { this.editor = new EditorAPI(findDOMNode(this.refs.contenteditable)) if (this.savedSelection && this.savedSelection.rawSelection.anchorNode) { this.editor.select(this.savedSelection) this.savedSelection = null } } } onInputChange = (event) => { const value = event.target.innerHTML this.savedSelection = this.editor.currentSelection().exportSelection() this.props.onSubjectChange(value) } onInputKeyDown = (event) => { if (['Enter', 'Return'].includes(event.key)) { event.stopPropagation() event.preventDefault() } } onDrop = (event) => { Handlers.onDrop('subject', {editor: this.editor, event}) } onDragOver = (event) => { Handlers.onDragOver({editor: this.editor, event}) } shouldAcceptDrop = (event) => { return Handlers.shouldAcceptDrop({event}) } focus() { const {isWorkspaceOpen} = this.props.sessionState if (isWorkspaceOpen) { findDOMNode(this.refs.contenteditable).focus() } else { this.refs.fallback.focus() } } renderContenteditable() { const {value} = this.props return (
) } render() { const {isWorkspaceOpen} = this.props.sessionState if (!isWorkspaceOpen) { const Fallback = this.props.fallback return } const {draft, session} = this.props const exposedProps = {draft, session} return ( {this.renderContenteditable()} ) } } export default ListensToMailMergeSession(MailMergeSubjectTextField) ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-table.jsx ================================================ import React, {PropTypes} from 'react' import {EditableTable} from 'nylas-component-kit' import {pickHTMLProps} from 'pick-react-known-prop' import MailMergeHeaderInput from './mail-merge-header-input' function InputRenderer(props) { const {isHeader, draftClientId} = props; if (!isHeader) { return } return } InputRenderer.propTypes = { isHeader: PropTypes.bool, defaultValue: PropTypes.string, draftClientId: PropTypes.string, } function MailMergeTable(props) { const {draftClientId} = props return (
) } MailMergeTable.propTypes = { tableDataSource: EditableTable.propTypes.tableDataSource, selection: PropTypes.object, draftClientId: PropTypes.string, onShiftSelection: PropTypes.func, } export default MailMergeTable ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-token-dnd-handlers.es6 ================================================ import {Utils} from 'nylas-exports' import {mailMergeSessionForDraft} from './mail-merge-draft-editing-session' import {DataTransferTypes, DragBehaviors} from './mail-merge-constants' function updateCursorPosition({editor, event}) { const {clientX, clientY} = event const range = document.caretRangeFromPoint(clientX, clientY); range.collapse() editor.select(range) return range } export function shouldAcceptDrop({event}) { const {dataTransfer} = event; return !!dataTransfer.getData(DataTransferTypes.ColIdx); } export function onDragOver({editor, event}) { updateCursorPosition({editor, event}) } export function onDrop(field, {editor, event}) { const {dataTransfer} = event const colIdx = dataTransfer.getData(DataTransferTypes.ColIdx) const colName = dataTransfer.getData(DataTransferTypes.ColName) const dragBehavior = dataTransfer.getData(DataTransferTypes.DragBehavior) const draftClientId = dataTransfer.getData(DataTransferTypes.DraftId) const mailMergeSession = mailMergeSessionForDraft(draftClientId) if (!mailMergeSession) { return } if (dragBehavior === DragBehaviors.Move) { const {tokenDataSource} = mailMergeSession.state const {tokenId} = tokenDataSource.findTokens(field, {colName, colIdx}).pop() || {} editor.removeCustomComponentByAnchorId(tokenId) } updateCursorPosition({editor, event}) const tokenId = Utils.generateTempId() editor.insertCustomComponent('MailMergeBodyToken', { field, colIdx, colName, tokenId, draftClientId, anchorId: tokenId, className: 'mail-merge-token-wrap', }) } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-token.jsx ================================================ import React, {PropTypes} from 'react' import classnames from 'classnames' import {RetinaImg} from 'nylas-component-kit' import {DataTransferTypes, DragBehaviors} from './mail-merge-constants' function onDragStart(event, {draftClientId, colIdx, colName, dragBehavior}) { const {dataTransfer} = event dataTransfer.effectAllowed = 'move' dataTransfer.setData(DataTransferTypes.DraftId, draftClientId) dataTransfer.setData(DataTransferTypes.ColIdx, colIdx) dataTransfer.setData(DataTransferTypes.ColName, colName) dataTransfer.setData(DataTransferTypes.DragBehavior, dragBehavior) } function MailMergeToken(props) { const {draftClientId, colIdx, colName, children, draggable, dragBehavior} = props const classes = classnames({ 'mail-merge-token': true, [`token-color-${colIdx % 5}`]: true, }) const _onDragStart = event => onDragStart(event, {draftClientId, colIdx, colName, dragBehavior}) const dragHandle = draggable ? : null; return ( {dragHandle} {children} ) } MailMergeToken.propTypes = { draftClientId: PropTypes.string, colIdx: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), colName: PropTypes.string, children: PropTypes.node, draggable: PropTypes.bool, dragBehavior: PropTypes.string, } MailMergeToken.defaultProps = { draggable: false, dragBehavior: DragBehaviors.Copy, } export default MailMergeToken ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-utils.es6 ================================================ import Papa from 'papaparse' import { Utils, Actions, Contact, RegExpUtils, DraftHelpers, DatabaseStore, SoundRegistry, } from 'nylas-exports' import {PLUGIN_ID, MAX_ROWS, DataTransferTypes, ParticipantFields} from './mail-merge-constants' import {mailMergeSessionForDraft} from './mail-merge-draft-editing-session' import SendManyDraftsTask from './send-many-drafts-task' export function contactFromColIdx(colIdx, email) { return new Contact({ name: email || '', email: email || 'No value selected', clientId: `${DataTransferTypes.ColIdx}:${colIdx}`, }) } export function colIdxFromContact(contact) { const {clientId} = contact if (!clientId.startsWith(DataTransferTypes.ColIdx)) { return null } return contact.clientId.split(':')[2] } export function tokenQuerySelector(tokenId) { if (!tokenId) { return `img.mail-merge-token-wrap` } return `img.mail-merge-token-wrap[data-overlay-id="${tokenId}"]` } export function tokenRegex(tokenId) { if (!tokenId) { // https://regex101.com/r/sU7sO6/1 return /]*?class="[^>]*?mail-merge-token-wrap[^>]*?"[^>]*?>/gim } // https://regex101.com/r/fJ5eN6/5 const reStr = `]*?class="[^>]*?mail-merge-token-wrap[^>]*?" [^>]*?data-overlay-id="${tokenId}"[^>]*?>` return new RegExp(reStr, 'gim') } function replaceContenteditableTokens(html, {field, tableDataSource, tokenDataSource, rowIdx}) { const replaced = tokenDataSource.tokensForField(field) .reduce((currentHtml, {colIdx, tokenId}) => { const fieldValue = tableDataSource.cellAt({rowIdx, colIdx}) || "" const markup = `${fieldValue}` return currentHtml.replace(tokenRegex(tokenId), markup) }, html) if (tokenRegex().test(replaced)) { throw new Error(`Field ${field} still contains tokens after attempting to replace for table values`) } return replaced } export function buildDraft(baseDraft, {tableDataSource, tokenDataSource, rowIdx}) { if (tableDataSource.isEmpty({rowIdx})) { return null } const draftToSend = baseDraft.clone() draftToSend.clientId = Utils.generateTempId() // Clear any previous mail merge metadata on the draft we are going to send // and add rowIdx draftToSend.applyPluginMetadata(PLUGIN_ID, {rowIdx}) // Replace tokens inside subject with values from table data const draftSubject = replaceContenteditableTokens(draftToSend.subject, { field: 'subject', rowIdx, tokenDataSource, tableDataSource, }) draftToSend.subject = Utils.extractTextFromHtml(draftSubject) // Replace tokens inside body with values from table data draftToSend.body = replaceContenteditableTokens(draftToSend.body, { field: 'body', rowIdx, tokenDataSource, tableDataSource, }) // Update participant values ParticipantFields.forEach((field) => { draftToSend[field] = tokenDataSource.tokensForField(field).map(({colIdx}) => { const column = tableDataSource.colAt(colIdx) const value = (tableDataSource.cellAt({rowIdx, colIdx}) || "").trim() const contact = new Contact({accountId: baseDraft.accountId, name: value, email: value}) if (!contact.isValid()) { throw new Error(`Can't send messages:\nThe column ${column} contains an invalid email address at row ${rowIdx + 1}: "${value}"`) } return contact }) }) return draftToSend } export function sendManyDrafts(mailMergeSession, recipientDrafts) { const transformedDrafts = []; return mailMergeSession.draftSession().ensureCorrectAccount() .then(() => { const baseDraft = mailMergeSession.draft(); return Promise.each(recipientDrafts, (recipientDraft) => { recipientDraft.accountId = baseDraft.accountId; recipientDraft.serverId = null; return DraftHelpers.applyExtensionTransforms(recipientDraft).then((transformed) => transformedDrafts.push(transformed) ); }); }) .then(() => DatabaseStore.inTransaction(t => t.persistModels(transformedDrafts)) ) .then(async () => { const baseDraft = mailMergeSession.draft(); if (baseDraft.uploads.length > 0) { recipientDrafts.forEach(async (d) => { await DraftHelpers.removeStaleUploads(d); }) } const recipientClientIds = recipientDrafts.map(d => d.clientId) Actions.queueTask(new SendManyDraftsTask(baseDraft.clientId, recipientClientIds)) if (NylasEnv.config.get("core.sending.sounds")) { SoundRegistry.playSound('hit-send'); } NylasEnv.close(); }) } export function sendMailMerge(draftClientId) { const mailMergeSession = mailMergeSessionForDraft(draftClientId) if (!mailMergeSession) { return } const baseDraft = mailMergeSession.draft() const {tableDataSource, tokenDataSource} = mailMergeSession.state const recipientDrafts = tableDataSource.rows() .map((row, rowIdx) => ( buildDraft(baseDraft, {tableDataSource, tokenDataSource, rowIdx}) )) .filter((draft) => draft != null) if (recipientDrafts.length === 0) { NylasEnv.showErrorDialog(`There are no drafts to send! Add add some data to the table below`) return } sendManyDrafts(mailMergeSession, recipientDrafts) } export function parseCSV(file, maxRows = MAX_ROWS) { return new Promise((resolve, reject) => { Papa.parse(file, { skipEmptyLines: true, complete: ({data}) => { if (data.length === 0) { NylasEnv.showErrorDialog( `The csv file you are trying to import contains no rows. Please select another file.` ); resolve(null) return; } // If a cell in the first row contains a valid email address, assume that // the table has no headers. We need row[0] to be field names, so make some up! const emailRegexp = RegExpUtils.emailRegex(); const emailInFirstRow = data[0].find((val) => emailRegexp.test(val)); if (emailInFirstRow) { const headers = data[0].map((val, idx) => { return emailInFirstRow === val ? 'Email Address' : `Column ${idx}` }) data.unshift(headers); } const columns = data[0].slice() const rows = data.slice(1) if (rows.length > maxRows) { NylasEnv.showErrorDialog( `The csv file you are trying to import contains more than the max allowed number of rows (${maxRows}).\nWe have only imported the first ${maxRows} rows` ); resolve({columns, rows: rows.slice(0, maxRows)}) return } resolve({columns, rows}) }, error: (error) => { NylasEnv.showErrorDialog(`Sorry, we were unable to parse the file: ${file.name}\n${error.message}`); reject(error) }, }) }) } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/mail-merge-workspace.jsx ================================================ import React, {Component, PropTypes} from 'react' import {RetinaImg, DropZone} from 'nylas-component-kit' import fs from 'fs'; import {parseCSV} from './mail-merge-utils' import MailMergeTable from './mail-merge-table' class MailMergeWorkspace extends Component { static displayName = 'MailMergeWorkspace' static propTypes = { isWorkspaceOpen: PropTypes.bool, tableDataSource: MailMergeTable.propTypes.tableDataSource, selection: PropTypes.object, draftClientId: PropTypes.string, session: PropTypes.object, } constructor() { super() this.state = {isDropping: false} } onDragStateChange = ({isDropping}) => { this.setState({isDropping}) } onChooseCSV = () => { NylasEnv.showOpenDialog({ properties: ['openFile'], filters: [ { name: 'CSV Files', extensions: ['csv', 'txt'] }, ], }, (pathsToOpen) => { if (!pathsToOpen || pathsToOpen.length === 0) { return; } fs.readFile(pathsToOpen[0], (err, contents) => { parseCSV(contents.toString()).then((tableData) => { this.loadCSV(tableData) }); }); }); } onDropCSV = (event) => { event.stopPropagation() const {dataTransfer} = event const file = dataTransfer.files[0] parseCSV(file) .then(tableData => this.loadCSV(tableData)) } loadCSV(newTableData) { const {tableDataSource, session} = this.props // TODO We need to reset the table values first because `EditableTable` does // not support controlled inputs, i.e. the inputs just use the // defaultValue props which will only apply when the input is empty session.clearTableData() session.loadTableData({newTableData, prevColumns: tableDataSource.columns()}) } shouldAcceptDrop = (event) => { event.stopPropagation() const {dataTransfer} = event if (dataTransfer.files.length === 1) { const file = dataTransfer.files[0] if (file.type === 'text/csv') { return true } } return false } renderSelectionControls() { const {selection, tableDataSource, session} = this.props const rows = tableDataSource.rows() return (
session.shiftSelection({row: -1})} >
session.shiftSelection({row: 1})} >
Recipient {selection.rowIdx + 1} of {rows.length}
Import CSV
) } renderDropCover() { const {isDropping} = this.state const display = isDropping ? 'block' : 'none'; return (
Drop to Import CSV
) } render() { const {session, draftClientId, isWorkspaceOpen, tableDataSource, selection, ...otherProps} = this.props if (!isWorkspaceOpen) { return false } return ( {this.renderDropCover()} {this.renderSelectionControls()} ) } } export default MailMergeWorkspace ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/main.es6 ================================================ import { TaskRegistry, ExtensionRegistry, ComponentRegistry, CustomContenteditableComponents, } from 'nylas-exports' import MailMergeButton from './mail-merge-button' import MailMergeContainer from './mail-merge-container' import SendManyDraftsTask from './send-many-drafts-task' import MailMergeSendButton from './mail-merge-send-button' import * as ComposerExtension from './mail-merge-composer-extension' import MailMergeSubjectTextField from './mail-merge-subject-text-field' import MailMergeBodyToken from './mail-merge-body-token' import MailMergeParticipantsTextField from './mail-merge-participants-text-field' export function activate() { TaskRegistry.register('SendManyDraftsTask', () => SendManyDraftsTask) ComponentRegistry.register(MailMergeContainer, {role: 'Composer:ActionBarWorkspace'}); ComponentRegistry.register(MailMergeButton, {role: 'Composer:ActionButton'}); ComponentRegistry.register(MailMergeSendButton, {role: 'Composer:SendActionButton'}); ComponentRegistry.register(MailMergeParticipantsTextField, {role: 'Composer:ParticipantsTextField'}); ComponentRegistry.register(MailMergeSubjectTextField, {role: 'Composer:SubjectTextField'}); CustomContenteditableComponents.register('MailMergeBodyToken', MailMergeBodyToken) ExtensionRegistry.Composer.register(ComposerExtension) } export function deactivate() { TaskRegistry.unregister('SendManyDraftsTask') ComponentRegistry.unregister(MailMergeContainer) ComponentRegistry.unregister(MailMergeButton) ComponentRegistry.unregister(MailMergeSendButton) ComponentRegistry.unregister(MailMergeParticipantsTextField) ComponentRegistry.unregister(MailMergeSubjectTextField) CustomContenteditableComponents.unregister('MailMergeBodyToken'); ExtensionRegistry.Composer.unregister(ComposerExtension) } export function serialize() { } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/selection-state-reducers.es6 ================================================ import _ from 'underscore' import {MAX_ROWS} from './mail-merge-constants' export function initialState(savedState) { if (savedState && savedState.tableDataSource) { return { selection: { rowIdx: 0, colIdx: 0, key: null, }, } } return { selection: { rowIdx: 0, colIdx: 0, key: 'Enter', }, } } export function clearTableData() { return { selection: { rowIdx: 0, colIdx: 0, key: null, }, } } export function loadTableData() { return { selection: { rowIdx: 0, colIdx: 0, key: null, }, } } export function addColumn({selection, tableDataSource}) { const columns = tableDataSource.columns() return { selection: { ...selection, rowIdx: null, colIdx: columns.length, key: 'Enter', }, } } export function removeLastColumn({selection, tableDataSource}) { const columns = tableDataSource.columns() const nextSelection = {...selection, key: null} if (nextSelection.colIdx === columns.length - 1) { nextSelection.colIdx-- } return {selection: nextSelection} } export function addRow({selection, tableDataSource}, {maxRows = MAX_ROWS} = {}) { const rows = tableDataSource.rows() if (rows.length === maxRows) { return {selection} } return { selection: { ...selection, rowIdx: rows.length, key: 'Enter', }, } } export function removeRow({selection, tableDataSource}) { const rows = tableDataSource.rows() const nextSelection = {...selection, key: null} if (nextSelection.rowIdx === rows.length - 1) { nextSelection.rowIdx-- } return {selection: nextSelection} } export function updateCell({selection}) { return { selection: {...selection, key: null}, } } export function setSelection({selection}, nextSelection) { if (_.isEqual(selection, nextSelection)) { return {selection} } return { selection: {...nextSelection}, } } function shift(len, idx, delta = 0) { const idxVal = idx != null ? idx : -1 return Math.min(len - 1, Math.max(0, idxVal + delta)) } export function shiftSelection({tableDataSource, selection}, deltas) { const rowLen = tableDataSource.rows().length const colLen = tableDataSource.columns().length const nextSelection = { rowIdx: shift(rowLen, selection.rowIdx, deltas.row), colIdx: shift(colLen, selection.colIdx, deltas.col), key: deltas.key, } return setSelection({selection}, nextSelection) } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/send-many-drafts-task.es6 ================================================ import { Task, Actions, Message, TaskQueue, DraftStore, BaseDraftTask, SendDraftTask, SoundRegistry, DatabaseStore, TaskQueueStatusStore, } from 'nylas-exports' import {PLUGIN_ID} from './mail-merge-constants' const SEND_DRAFT_THROTTLE = 500 export default class SendManyDraftsTask extends Task { constructor(baseDraftClientId, draftIdsToSend = []) { super() this.baseDraftClientId = baseDraftClientId this.draftIdsToSend = draftIdsToSend this.queuedDraftIds = new Set() this.failedDraftIds = [] } label() { return `Sending ${this.draftIdsToSend.length} messages` } shouldDequeueOtherTask(other) { return other instanceof SendManyDraftsTask && other.draftClientId === this.baseDraftClientId; } isDependentOnTask(other) { const isSameDraft = other.draftClientId === this.baseDraftClientId; const isSaveOrSend = other instanceof BaseDraftTask; return isSameDraft && isSaveOrSend } performLocal() { if (!this.baseDraftClientId) { const errMsg = `Attempt to call SendManyDraftsTask.performLocal without a baseDraftClientId`; return Promise.reject(new Error(errMsg)); } if (this.draftIdsToSend.length === 0) { const errMsg = `Attempt to call SendManyDraftsTask.performLocal without draftIdsToSend`; return Promise.reject(new Error(errMsg)); } return Promise.resolve(); } performRemote() { const unqueuedDraftIds = this.draftIdsToSend.filter(id => !this.queuedDraftIds.has(id)) if (unqueuedDraftIds.length > 0) { return ( DatabaseStore.modelify(Message, unqueuedDraftIds) .then((draftsToSend) => this.queueSendTasks(draftsToSend)) .then(() => this.waitForSendTasks()) .then(() => this.onTasksProcessed()) .catch((error) => this.handleError(error)) ) } return ( this.waitForSendTasks() .then(() => this.onTasksProcessed()) .catch((error) => this.handleError(error)) ) } queueSendTasks(draftsToSend, throttle = SEND_DRAFT_THROTTLE) { return Promise.each(draftsToSend, (draft) => { return new Promise((resolve) => { const task = new SendDraftTask(draft.clientId, { playSound: false, emitError: false, allowMultiSend: false, }) Actions.queueTask(task) this.queuedDraftIds.add(draft.clientId) setTimeout(resolve, throttle) }) }) } waitForSendTasks() { const waitForTaskPromises = Array.from(this.queuedDraftIds).map((draftClientId) => { const tasks = TaskQueue.allTasks() const task = tasks.find((t) => t instanceof SendDraftTask && t.draftClientId === draftClientId) if (!task) { console.warn(`SendManyDraftsTask: Can't find queued SendDraftTask for draft id: ${draftClientId}`) this.queuedDraftIds.delete(draftClientId) return Promise.resolve() } return TaskQueueStatusStore.waitForPerformRemote(task) .then((completedTask) => { if (!this.queuedDraftIds.has(completedTask.draftClientId)) { return } const {status} = completedTask.queueState if (status === Task.Status.Failed) { this.failedDraftIds.push(completedTask.draftClientId) } this.queuedDraftIds.delete(completedTask.draftClientId) }) }) return Promise.all(waitForTaskPromises) } onTasksProcessed() { if (this.failedDraftIds.length > 0) { const error = new Error( `Sorry, some of your messages failed to send. This could be due to sending limits imposed by your mail provider. Please try again after a while. Also make sure your messages are addressed correctly and are not too large.`, ) return this.handleError(error) } Actions.recordUserEvent("Mail Merge Sent", { numItems: this.draftIdsToSend.length, numFailedItems: this.failedDraftIds.length, }) if (NylasEnv.config.get("core.sending.sounds")) { SoundRegistry.playSound('send'); } return Promise.resolve(Task.Status.Success) } handleError(error) { return ( DraftStore.sessionForClientId(this.baseDraftClientId) .then((session) => { return DatabaseStore.modelify(Message, this.failedDraftIds) .then((failedDrafts) => { const failedDraftRowIdxs = failedDrafts.map((draft) => draft.metadataForPluginId(PLUGIN_ID).rowIdx) const currentMetadata = session.draft().metadataForPluginId(PLUGIN_ID) const nextMetadata = { ...currentMetadata, failedDraftRowIdxs, } session.changes.addPluginMetadata(PLUGIN_ID, nextMetadata) return session.changes.commit() }) }) .then(() => { this.failedDraftIds.forEach((id) => Actions.destroyDraft(id)) Actions.composePopoutDraft(this.baseDraftClientId, {errorMessage: error.message}) return Promise.resolve([Task.Status.Failed, error]) }) ) } toJSON() { const json = {...super.toJSON()} json.queuedDraftIds = Array.from(json.queuedDraftIds) return json } fromJSON(json) { const result = super.fromJSON(json) result.queuedDraftIds = new Set(result.queuedDraftIds) return result } } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/table-state-reducers.es6 ================================================ import {Table} from 'nylas-component-kit' import {MAX_ROWS} from './mail-merge-constants' const {TableDataSource} = Table export function toJSON({tableDataSource}) { return { tableDataSource: tableDataSource.toJSON(), } } export function fromJSON({tableDataSource}) { return { tableDataSource: new TableDataSource(tableDataSource), } } export function initialState(savedState) { if (savedState && savedState.tableDataSource instanceof TableDataSource) { if (savedState.failedDraftRowIdxs) { const failedRowIdxs = new Set(savedState.failedDraftRowIdxs) const dataSource = ( savedState.tableDataSource .filterRows((row, idx) => failedRowIdxs.has(idx)) ) return { tableDataSource: dataSource, } } return { tableDataSource: savedState.tableDataSource, } } return { tableDataSource: new TableDataSource({ columns: ['email'], rows: [ [null], ], }), } } export function clearTableData({tableDataSource}) { return { tableDataSource: tableDataSource.clear(), } } export function loadTableData({tableDataSource}, {newTableData}) { const newRows = newTableData.rows const newCols = newTableData.columns if (newRows.length === 0 || newCols.length === 0) { return initialState() } return { tableDataSource: new TableDataSource(newTableData), } } export function addColumn({tableDataSource}) { return { tableDataSource: tableDataSource.addColumn(), } } export function removeLastColumn({tableDataSource}) { return { tableDataSource: tableDataSource.removeLastColumn(), } } export function addRow({tableDataSource}, {maxRows = MAX_ROWS} = {}) { const rows = tableDataSource.rows() if (rows.length === maxRows) { return {tableDataSource} } return { tableDataSource: tableDataSource.addRow(), } } export function removeRow({tableDataSource}) { return { tableDataSource: tableDataSource.removeRow(), } } export function updateCell({tableDataSource}, {rowIdx, colIdx, isHeader, value}) { return { tableDataSource: tableDataSource.updateCell({rowIdx, colIdx, isHeader, value}), } } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/token-data-source.es6 ================================================ import _ from 'underscore' import {Utils} from 'nylas-exports' class FieldTokens { constructor(field, tokens = {}) { this._field = field this._tokens = tokens } linkToken(colProps) { const tokenId = colProps.tokenId ? colProps.tokenId : Utils.generateTempId() return new FieldTokens(this._field, { ...this._tokens, [tokenId]: {...colProps, field: this._field, tokenId}, }) } unlinkToken(tokenId) { const nextTokens = {...this._tokens} delete nextTokens[tokenId] return new FieldTokens(this._field, nextTokens) } updateToken(tokenId, props) { const token = this._tokens[tokenId] return new FieldTokens(this._field, { ...this._tokens, [tokenId]: {...token, ...props}, }) } tokens() { return _.values(this._tokens) } findTokens(matcher) { return _.where(this.tokens(), matcher) } getToken(tokenId) { return this._tokens[tokenId] } } class TokenDataSource { static fromJSON(json) { return json.reduce((dataSource, token) => { const {field, ...props} = token return dataSource.linkToken(field, props) }, new TokenDataSource()) } constructor(linkedTokensByField = {}) { this._linkedTokensByField = linkedTokensByField } findTokens(field, matcher) { if (!this._linkedTokensByField[field]) { return [] } return this._linkedTokensByField[field].findTokens(matcher) } tokensForField(field) { if (!this._linkedTokensByField[field]) { return [] } return this._linkedTokensByField[field].tokens() } getToken(field, tokenId) { if (!this._linkedTokensByField[field]) { return null } return this._linkedTokensByField[field].getToken(tokenId) } linkToken(field, props) { if (!this._linkedTokensByField[field]) { this._linkedTokensByField[field] = new FieldTokens(field) } const current = this._linkedTokensByField[field] return new TokenDataSource({ ...this._linkedTokensByField, [field]: current.linkToken(props), }) } unlinkToken(field, tokenId) { if (!this._linkedTokensByField[field]) { return this } const current = this._linkedTokensByField[field] return new TokenDataSource({ ...this._linkedTokensByField, [field]: current.unlinkToken(tokenId), }) } updateToken(field, tokenId, props) { if (!this._linkedTokensByField[field]) { return this } const current = this._linkedTokensByField[field] return new TokenDataSource({ ...this._linkedTokensByField, [field]: current.updateToken(tokenId, props), }) } toJSON() { return Object.keys(this._linkedTokensByField) .map((field) => this._linkedTokensByField[field]) .reduce((prevTokens, dataSource) => prevTokens.concat(dataSource.tokens()), []) } } export default TokenDataSource ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/token-state-reducers.es6 ================================================ import {contactFromColIdx} from './mail-merge-utils' import TokenDataSource from './token-data-source' import {LinkableFields, ContenteditableFields, ParticipantFields} from './mail-merge-constants' export function toDraftChanges(draft, {tableDataSource, selection, tokenDataSource}) { // Save the participant fields to fake Contacts const participantChanges = {} ParticipantFields.forEach((field) => ( participantChanges[field] = tokenDataSource.tokensForField(field).map(({colIdx}) => { const selectionValue = tableDataSource.cellAt({rowIdx: selection.rowIdx, colIdx}) || "" return contactFromColIdx(colIdx, selectionValue.trim()) }) )) // Save the body and subject if they haven't been saved yet // This is necessary because new tokens wont be saved to the contenteditable // unless the user directly mutates the body or subject const contenteditableChanges = {} ContenteditableFields.forEach((field) => { const node = document.querySelector(`.${field}-field [contenteditable]`) if (node) { const latestValue = node.innerHTML if (draft[field] !== latestValue) { contenteditableChanges[field] = latestValue } } }) return {...participantChanges, ...contenteditableChanges} } export function toJSON({tokenDataSource}) { return {tokenDataSource: tokenDataSource.toJSON()} } export function fromJSON({tokenDataSource}) { return {tokenDataSource: TokenDataSource.fromJSON(tokenDataSource)} } export function initialState(savedData) { if (savedData && savedData.tokenDataSource) { return { tokenDataSource: savedData.tokenDataSource, } } const tokenDataSource = new TokenDataSource() return { tokenDataSource } } export function loadTableData({tokenDataSource}, {newTableData}) { const nextColumns = newTableData.columns let nextTokenDataSource = new TokenDataSource() // When loading table data, if the new table data contains columns with the same // name, make sure to keep those tokens in our state with the updated position // of the column LinkableFields.forEach((field) => { const currentTokens = tokenDataSource.tokensForField(field) currentTokens.forEach((link) => { const {colName, ...props} = link const newColIdx = nextColumns.indexOf(colName) if (newColIdx !== -1) { nextTokenDataSource = nextTokenDataSource.linkToken(field, { ...props, colName, colIdx: newColIdx, }) } }) }) return {tokenDataSource: nextTokenDataSource} } export function linkToDraft({tokenDataSource}, args) { const {colIdx, colName, field, ...props} = args if (!field) { throw new Error('MailMerge: Must provide `field` to `linkToDraft`') } if (!colIdx) { throw new Error('MailMerge: Must provide `colIdx` to `linkToDraft`') } if (colName == null) { throw new Error('MailMerge: Must provide `colName` to `linkToDraft`') } return { tokenDataSource: tokenDataSource.linkToken(field, {colIdx, colName, ...props}), } } export function unlinkFromDraft({tokenDataSource}, {field, tokenId}) { if (!field) { throw new Error('MailMerge: Must provide `field` to `linkToDraft`') } if (!tokenId) { throw new Error('MailMerge: Must provide `tokenId` to `linkToDraft`') } return { tokenDataSource: tokenDataSource.unlinkToken(field, tokenId), } } export function removeLastColumn({tokenDataSource, tableDataSource}) { const colIdx = tableDataSource.columns().length - 1 const colName = tableDataSource.colAt(colIdx) let nextTokenDataSource = tokenDataSource // Unlink any fields that where linked to the column that is being removed LinkableFields.forEach((field) => { const tokensToRemove = tokenDataSource.findTokens(field, {colName}) nextTokenDataSource = tokensToRemove.reduce((prevTokenDataSource, {tokenId}) => { return prevTokenDataSource.unlinkToken(field, tokenId) }, nextTokenDataSource) }) return {tokenDataSource: nextTokenDataSource} } export function updateCell({tokenDataSource, tableDataSource}, {colIdx, isHeader, value}) { if (!isHeader) { return {tokenDataSource} } const currentColName = tableDataSource.colAt(colIdx) let nextTokenDataSource = tokenDataSource // Update any tokens that referenced the column name that is being updated LinkableFields.forEach((field) => { const tokens = tokenDataSource.findTokens(field, {colName: currentColName}) tokens.forEach(({tokenId}) => { nextTokenDataSource = nextTokenDataSource.updateToken(field, tokenId, {colName: value}) }) }) return {tokenDataSource: nextTokenDataSource} } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/lib/workspace-state-reducers.es6 ================================================ export function initialState(savedData) { if (savedData && savedData.tokenDataSource && savedData.tableDataSource) { return { isWorkspaceOpen: true, } } return { isWorkspaceOpen: false, } } export function toggleWorkspace({isWorkspaceOpen}) { return {isWorkspaceOpen: !isWorkspaceOpen} } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/package.json ================================================ { "name": "composer-mail-merge", "title":"Mail Merge", "description": "Send personalized emails at scale using CSV-formatted data.", "main": "./lib/main", "isHiddenOnPluginsPage": true, "version": "0.1.0", "engines": { "nylas": "*" }, "icon": "./icon.png", "isOptional": true, "supportedEnvs": ["production", "staging"], "windowTypes": { "default": true, "composer": true, "work": true, "thread-popout": true }, "license": "GPL-3.0", "dependencies": { "papaparse": "^4.1.2" } } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/fixtures.es6 ================================================ import {Table} from 'nylas-component-kit' import TokenDataSource from '../lib/token-data-source' const {TableDataSource} = Table export const testData = { columns: ['name', 'email'], rows: [ ['donald', 'donald@nylas.com'], ['hilary', 'hilary@nylas.com'], ], } export const testDataSource = new TableDataSource(testData) export const testSelection = {rowIdx: 1, colIdx: 0, key: 'Enter'} export const testTokenDataSource = new TokenDataSource() .linkToken('to', {colName: 'name', colIdx: 0, tokenId: 'name-0'}) .linkToken('bcc', {colName: 'email', colIdx: 1, tokenId: 'email-1'}) export const testState = { isWorkspaceOpen: true, selection: testSelection, tableDataSource: testDataSource, tokenDataSource: testTokenDataSource, } export const testAnchorMarkup = (tokenId) => { return `` } export const testContenteditableContent = () => { const nameSpan = testAnchorMarkup('name-anchor') const emailSpan = testAnchorMarkup('email-anchor') return `
${nameSpan}
stuff${emailSpan}
` } ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/mail-merge-draft-editing-session-spec.es6 ================================================ import {Message} from 'nylas-exports' import {MailMergeDraftEditingSession} from '../lib/mail-merge-draft-editing-session' const testReducers = [ {testAction: state => ({...state, val1: 'reducer1'})}, {testAction: state => ({...state, val2: 'reducer2'})}, ] const draftModel = new Message() const draftSess = { draft() { return draftModel }, } describe('MailMergeDraftEditingSession', function describeBlock() { let mailMergeSess; beforeEach(() => { mailMergeSess = new MailMergeDraftEditingSession(draftSess, testReducers) }); describe('dispatch', () => { it('computes next state correctly based on registered reducers', () => { const nextState = mailMergeSess.dispatch({name: 'testAction'}, {}) expect(nextState).toEqual({ val1: 'reducer1', val2: 'reducer2', }) }); it('computes state value for key correctly when 2 reducers ', () => { const reducers = testReducers.concat([ {testAction: state => ({...state, val2: 'reducer3'})}, ]) mailMergeSess = new MailMergeDraftEditingSession(draftSess, reducers) const nextState = mailMergeSess.dispatch({name: 'testAction'}, {}) expect(nextState).toEqual({ val1: 'reducer1', val2: 'reducer3', }) }); it('passes arguments correctly to reducers', () => { const args = ['arg1'] const reducers = testReducers.concat([ {testAction: (state, arg) => ({...state, val3: arg})}, ]) mailMergeSess = new MailMergeDraftEditingSession(draftSess, reducers) const nextState = mailMergeSess.dispatch({name: 'testAction', args}, {}) expect(nextState).toEqual({ val1: 'reducer1', val2: 'reducer2', val3: 'arg1', }) }); }); describe('initializeState', () => { it('loads any saved metadata on the draft', () => { const savedMetadata = { tableDataSource: {}, tokenDataSource: {}, } const nextState = {next: 'state'} spyOn(draftModel, 'metadataForPluginId').andReturn(savedMetadata) spyOn(mailMergeSess, 'dispatch').andReturn(nextState) mailMergeSess.initializeState(draftModel) expect(mailMergeSess.dispatch.calls.length).toBe(2) const args1 = mailMergeSess.dispatch.calls[0].args const args2 = mailMergeSess.dispatch.calls[1].args expect(args1).toEqual([{name: 'fromJSON'}, savedMetadata]) expect(args2).toEqual([{name: 'initialState'}, nextState]) expect(mailMergeSess._state).toEqual(nextState) }); it('does not laod saved metadata if saved metadata is incorrect', () => { const savedMetadata = { tableDataSource: {}, } const nextState = {next: 'state'} spyOn(draftModel, 'metadataForPluginId').andReturn(savedMetadata) spyOn(mailMergeSess, 'dispatch').andReturn(nextState) mailMergeSess.initializeState(draftModel) expect(mailMergeSess.dispatch.calls.length).toBe(1) const {args} = mailMergeSess.dispatch.calls[0] expect(args).toEqual([{name: 'initialState'}]) expect(mailMergeSess._state).toEqual(nextState) }); it('just loads initial state if no metadata is saved on the draft', () => { const savedMetadata = {} const nextState = {next: 'state'} spyOn(draftModel, 'metadataForPluginId').andReturn(savedMetadata) spyOn(mailMergeSess, 'dispatch').andReturn(nextState) mailMergeSess.initializeState(draftModel) expect(mailMergeSess.dispatch.calls.length).toBe(1) const {args} = mailMergeSess.dispatch.calls[0] expect(args).toEqual([{name: 'initialState'}]) expect(mailMergeSess._state).toEqual(nextState) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/mail-merge-utils-spec.es6 ================================================ import Papa from 'papaparse' import { Message, Contact, DraftHelpers, Actions, DatabaseWriter, } from 'nylas-exports'; import {DataTransferTypes} from '../lib/mail-merge-constants' import SendManyDraftsTask from '../lib/send-many-drafts-task' import { parseCSV, buildDraft, sendManyDrafts, contactFromColIdx, } from '../lib/mail-merge-utils' import { testData, testDataSource, testAnchorMarkup, testContenteditableContent, } from './fixtures' import TokenDataSource from '../lib/token-data-source' xdescribe('MailMergeUtils', function describeBlock() { describe('contactFromColIdx', () => { it('creates a contact with the correct values', () => { const email = 'email@email.com' const contact = contactFromColIdx(0, email) expect(contact instanceof Contact).toBe(true) expect(contact.email).toBe(email) expect(contact.name).toBe(email) expect(contact.clientId).toBe(`${DataTransferTypes.ColIdx}:0`) }); }); describe('buildDraft', () => { beforeEach(() => { this.baseDraft = new Message({ draft: true, clientId: 'd1', subject: `
Your email is: ${testAnchorMarkup('subject-email-anchor')}`, body: testContenteditableContent(), }) this.tokenDataSource = new TokenDataSource() .linkToken('to', {colName: 'email', colIdx: 1, tokenId: 'email-0'}) .linkToken('bcc', {colName: 'email', colIdx: 1, tokenId: 'email-1'}) .linkToken('body', {colName: 'name', colIdx: 0, tokenId: 'name-anchor'}) .linkToken('body', {colName: 'email', colIdx: 1, tokenId: 'email-anchor'}) .linkToken('subject', {colName: 'email', colIdx: 1, tokenId: 'subject-email-anchor'}) }); it('creates a draft with the correct subject based on linked columns and rowIdx', () => { const draft = buildDraft(this.baseDraft, { rowIdx: 1, tableDataSource: testDataSource, tokenDataSource: this.tokenDataSource, }) expect(draft.subject).toEqual('Your email is: hilary@nylas.com') }); it('creates a draft with the correct body based on linked columns and rowIdx', () => { const draft = buildDraft(this.baseDraft, { rowIdx: 1, tableDataSource: testDataSource, tokenDataSource: this.tokenDataSource, }) expect(draft.body).toEqual('
hilary
stuffhilary@nylas.com
') }); it('creates a draft with the correct participants based on linked columns and rowIdx', () => { const draft = buildDraft(this.baseDraft, { rowIdx: 1, tableDataSource: testDataSource, tokenDataSource: this.tokenDataSource, }) expect(draft.to[0].email).toEqual('hilary@nylas.com') expect(draft.bcc[0].email).toEqual('hilary@nylas.com') }); it('throws error if value for participant field in invalid email address', () => { this.tokenDataSource = this.tokenDataSource.updateToken('to', 'email-0', {colName: 'name', colIdx: 0}) expect(() => { buildDraft(this.baseDraft, { rowIdx: 1, tableDataSource: testDataSource, tokenDataSource: this.tokenDataSource, }) }).toThrow() }); }); describe('sendManyDrafts', () => { beforeEach(() => { this.baseDraft = new Message({ draft: true, accountId: '123', serverId: '111', clientId: 'local-111', }) this.drafts = [ new Message({draft: true, clientId: 'local-d1'}), new Message({draft: true, clientId: 'local-d2'}), new Message({draft: true, clientId: 'local-d3'}), ] this.draftSession = { ensureCorrectAccount: jasmine.createSpy('ensureCorrectAccount').andCallFake(() => { return Promise.resolve() }), } this.session = { draftSession: () => this.draftSession, draft: () => this.baseDraft, } spyOn(DraftHelpers, 'applyExtensionTransforms').andCallFake((d) => { const transformed = d.clone() transformed.body = 'transformed' return Promise.resolve(transformed) }) spyOn(DatabaseWriter.prototype, 'persistModels').andReturn(Promise.resolve()) spyOn(Actions, 'queueTask') spyOn(Actions, 'queueTasks') spyOn(NylasEnv.config, 'get').andReturn(false) spyOn(NylasEnv, 'close') }) it('ensures account is correct', () => { waitsForPromise(() => { return sendManyDrafts(this.session, this.drafts) .then(() => { expect(this.draftSession.ensureCorrectAccount).toHaveBeenCalled() }) }) }); it('applies extension transforms to each draft and saves them', () => { waitsForPromise(() => { return sendManyDrafts(this.session, this.drafts) .then(() => { const transformedDrafts = DatabaseWriter.prototype.persistModels.calls[0].args[0] expect(transformedDrafts.length).toBe(3) transformedDrafts.forEach((d) => { expect(d.body).toBe('transformed') expect(d.accountId).toBe('123') expect(d.serverId).toBe(null) }) }) }) }); it('queues the correct task', () => { waitsForPromise(() => { return sendManyDrafts(this.session, this.drafts) .then(() => { const task = Actions.queueTask.calls[0].args[0] expect(task instanceof SendManyDraftsTask).toBe(true) expect(task.baseDraftClientId).toBe('local-111') expect(task.draftIdsToSend).toEqual(['local-d1', 'local-d2', 'local-d3']) }) }) }); }); describe('parseCSV', () => { beforeEach(() => { spyOn(NylasEnv, 'showErrorDialog') }); it('shows error when csv file is empty', () => { spyOn(Papa, 'parse').andCallFake((file, {complete}) => { complete({data: []}) }) waitsForPromise(() => { return parseCSV() .then((data) => { expect(NylasEnv.showErrorDialog).toHaveBeenCalled() expect(data).toBe(null) }) }) }); it('returns the correct table data', () => { spyOn(Papa, 'parse').andCallFake((file, {complete}) => { complete({data: [testData.columns].concat(testData.rows)}) }) waitsForPromise(() => { return parseCSV() .then((data) => { expect(data).toEqual(testData) }) }) }); it('adds a header row if the first row contains a value that resembles an email', () => { spyOn(Papa, 'parse').andCallFake((file, {complete}) => { complete({data: [...testData.rows]}) }) waitsForPromise(() => { return parseCSV() .then((data) => { expect(data).toEqual({ columns: ['Column 0', 'Email Address'], rows: testData.rows, }) }) }) }); it('only imports MAX_ROWS number of rows', () => { spyOn(Papa, 'parse').andCallFake((file, {complete}) => { complete({ data: [testData.columns].concat([...testData.rows, ['extra', 'col@email.com']]), }) }) waitsForPromise(() => { return parseCSV(null, 2) .then((data) => { expect(data.rows.length).toBe(2) expect(data).toEqual(testData) expect(NylasEnv.showErrorDialog).toHaveBeenCalled() }) }) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/selection-state-reducers-spec.es6 ================================================ import { clearTableData, loadTableData, addColumn, removeLastColumn, addRow, removeRow, updateCell, setSelection, shiftSelection, } from '../lib/selection-state-reducers' import {testState, testSelection} from './fixtures' describe('SelectionStateReducers', function describeBlock() { describe('clearTableData', () => { it('sets selection correctly', () => { const {selection} = clearTableData() expect(selection).toEqual({ rowIdx: 0, colIdx: 0, key: null, }) }); }); describe('loadTableData', () => { it('sets selection correctly', () => { const {selection} = loadTableData() expect(selection).toEqual({ rowIdx: 0, colIdx: 0, key: null, }) }); }); describe('addColumn', () => { it('sets selection to the header and last column', () => { const {selection} = addColumn(testState) expect(selection).toEqual({rowIdx: null, colIdx: 2, key: 'Enter'}) }); }); describe('removeLastColumn', () => { it('only sets key to null if selection is not in last column', () => { const {selection} = removeLastColumn(testState) expect(selection).toEqual({...testSelection, key: null}) }); it('decreases col selection by 1 if selection is currently in last column', () => { const {selection} = removeLastColumn({...testState, selection: {rowIdx: 1, colIdx: 1, key: 'Enter'}}) expect(selection).toEqual({rowIdx: 1, colIdx: 0, key: null}) }); }); describe('addRow', () => { it('does nothing if MAX_ROWS reached', () => { const {selection} = addRow(testState, {maxRows: 2}) expect(selection).toBe(testSelection) }); it('sets selection to last row', () => { const {selection} = addRow(testState, {maxRows: 3}) expect(selection).toEqual({rowIdx: 2, colIdx: 0, key: 'Enter'}) }); }); describe('removeRow', () => { it('only sets key to null if selection is not in last row', () => { const {selection} = removeRow(testState) expect(selection).toEqual({...testSelection, rowIdx: 0, key: null}) }); it('decreases row selection by 1 if selection is currently in last row', () => { const {selection} = removeRow({...testState, selection: {rowIdx: 1, colIdx: 1, key: 'Enter'}}) expect(selection).toEqual({rowIdx: 0, colIdx: 1, key: null}) }); }); describe('updateCell', () => { it('sets selection key to null (wont make input focus)', () => { const {selection} = updateCell(testState) expect(selection.key).toBe(null) }); }); describe('setSelection', () => { it('sets the selection to the given selection if selection has changed', () => { const {selection} = setSelection(testState, {rowIdx: 1, colIdx: 1, key: null}) expect(selection).toEqual({rowIdx: 1, colIdx: 1, key: null}) }); it('returns same selection otherwise', () => { const {selection} = setSelection(testState, {...testSelection}) expect(selection).toBe(testSelection) }); }); describe('shiftSelection', () => { it('sets the given key', () => { const {selection} = shiftSelection(testState, {row: 0, col: 0, key: null}) expect(selection.key).toBe(null) }); it('shifts row selection correctly when rowIdx is null (header)', () => { let nextSelection = shiftSelection({ ...testState, selection: {rowIdx: null, col: 0}, }, {row: 1}).selection expect(nextSelection.rowIdx).toBe(0) nextSelection = shiftSelection({ ...testState, selection: {rowIdx: null, col: 0}, }, {row: 2}).selection expect(nextSelection.rowIdx).toBe(1) nextSelection = shiftSelection({ ...testState, selection: {rowIdx: null, col: 0}, }, {row: -1}).selection expect(nextSelection.rowIdx).toBe(0) }); it('shifts row selection by correct value', () => { let nextState = shiftSelection( testState, {row: -1} ) expect(nextState.selection.rowIdx).toBe(0) nextState = shiftSelection( {...testState, selection: {rowIdx: 0, colIdx: 0, key: 'Enter'}}, {row: 1} ) expect(nextState.selection.rowIdx).toBe(1) }); it('does not shift row selection when at the edges', () => { let nextState = shiftSelection( testState, {row: 2} ) expect(nextState.selection.rowIdx).toBe(1) nextState = shiftSelection( {...testState, selection: {rowIdx: 0, colIdx: 0, key: 'Enter'}}, {row: -2} ) expect(nextState.selection.rowIdx).toBe(0) }); it('shifts col selection by correct value', () => { let nextState = shiftSelection( testState, {col: 1} ) expect(nextState.selection.colIdx).toBe(1) nextState = shiftSelection( {...testState, selection: {rowIdx: 0, colIdx: 1, key: 'Enter'}}, {col: -1} ) expect(nextState.selection.colIdx).toBe(0) }); it('does not shift col selection when at the edges', () => { let nextState = shiftSelection( testState, {col: -2} ) expect(nextState.selection.colIdx).toBe(0) nextState = shiftSelection( {...testState, selection: {rowIdx: 0, colIdx: 1, key: 'Enter'}}, {col: 2} ) expect(nextState.selection.colIdx).toBe(1) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/send-many-drafts-task-spec.es6 ================================================ import { Task, Actions, Message, TaskQueue, DraftStore, DatabaseStore, SendDraftTask, TaskQueueStatusStore, } from 'nylas-exports' import SendManyDraftsTask from '../lib/send-many-drafts-task' import {PLUGIN_ID} from '../lib/mail-merge-constants' xdescribe('SendManyDraftsTask', function describeBlock() { beforeEach(() => { this.baseDraft = new Message({ clientId: 'baseId', files: ['f1', 'f2'], uploads: [], }) this.d1 = new Message({ clientId: 'd1', uploads: ['u1'], }) this.d2 = new Message({ clientId: 'd2', }) this.task = new SendManyDraftsTask('baseId', ['d1', 'd2']) spyOn(DatabaseStore, 'modelify').andReturn(Promise.resolve([this.baseDraft, this.d1, this.d2])) spyOn(DatabaseStore, 'inTransaction').andCallFake((cb) => { return cb({persistModels() { return Promise.resolve() }}) }) }); describe('performRemote', () => { beforeEach(() => { spyOn(this.task, 'prepareDraftsToSend').andCallFake((baseId, draftIds) => { return Promise.resolve(draftIds.map(id => this[id])) }) spyOn(this.task, 'queueSendTasks').andReturn(Promise.resolve()) spyOn(this.task, 'waitForSendTasks').andReturn(Promise.resolve()) spyOn(this.task, 'onTasksProcessed') spyOn(this.task, 'handleError').andCallFake((error) => Promise.resolve([Task.Status.Failed, error]) ) }); it('queues all drafts for sending when no tasks have been queued yet', () => { waitsForPromise(() => { return this.task.performRemote() .then(() => { expect(this.task.prepareDraftsToSend).toHaveBeenCalledWith('baseId', ['d1', 'd2']) expect(this.task.queueSendTasks).toHaveBeenCalledWith([this.d1, this.d2]) expect(this.task.waitForSendTasks).toHaveBeenCalled() }) }) }); it('only queues drafts that have not been queued for sending', () => { this.task.queuedDraftIds = new Set(['d1']) waitsForPromise(() => { return this.task.performRemote() .then(() => { expect(this.task.prepareDraftsToSend).toHaveBeenCalledWith('baseId', ['d2']) expect(this.task.queueSendTasks).toHaveBeenCalledWith([this.d2]) expect(this.task.waitForSendTasks).toHaveBeenCalled() }) }) }); it('only waits for tasks to complete when all drafts have been queued for sending', () => { this.task.queuedDraftIds = new Set(['d1', 'd2']) waitsForPromise(() => { return this.task.performRemote() .then(() => { expect(this.task.prepareDraftsToSend).not.toHaveBeenCalled() expect(this.task.queueSendTasks).not.toHaveBeenCalled() expect(this.task.waitForSendTasks).toHaveBeenCalled() }) }) }); it('handles errors', () => { jasmine.unspy(this.task, 'onTasksProcessed') spyOn(this.task, 'onTasksProcessed').andReturn(Promise.reject(new Error('Oh no!'))) this.task.queuedDraftIds = new Set(['d1', 'd2']) waitsForPromise(() => { return this.task.performRemote() .then(() => { expect(this.task.handleError).toHaveBeenCalled() }) }) }); }); describe('prepareDraftsToSend', () => { it('updates the files and uploads on each draft to send', () => { waitsForPromise(() => { return this.task.prepareDraftsToSend('baseId', ['d1', 'd2']) .then((draftsToSend) => { expect(DatabaseStore.modelify).toHaveBeenCalledWith(Message, ['baseId', 'd1', 'd2']) expect(draftsToSend.length).toBe(2) expect(draftsToSend[0].files).toEqual(this.baseDraft.files) expect(draftsToSend[0].uploads).toEqual([]) expect(draftsToSend[1].files).toEqual(this.baseDraft.files) expect(draftsToSend[1].uploads).toEqual([]) }) }) }); }); describe('queueSendTasks', () => { beforeEach(() => { spyOn(Actions, 'queueTask') }); it('queues SendDraftTask for all passed in drafts', () => { waitsForPromise(() => { const promise = this.task.queueSendTasks([this.d1, this.d2], 0) advanceClock(1) advanceClock(1) return promise.then(() => { expect(Actions.queueTask.calls.length).toBe(2) expect(Array.from(this.task.queuedDraftIds)).toEqual(['d1', 'd2']) Actions.queueTask.calls.forEach(({args}, idx) => { const task = args[0] expect(task instanceof SendDraftTask).toBe(true) expect(task.draftClientId).toEqual(`d${idx + 1}`) }) }) }) }); }); describe('waitForSendTasks', () => { it('it updates queuedDraftIds and warns if there are no tasks matching the draft client id', () => { this.task.queuedDraftIds = new Set(['d2']) spyOn(TaskQueue, 'allTasks').andReturn([]) spyOn(console, 'warn') waitsForPromise(() => { return this.task.waitForSendTasks() .then(() => { expect(this.task.queuedDraftIds.size).toBe(0) expect(console.warn).toHaveBeenCalled() }) }) }); it('resolves when all queued tasks complete', () => { this.task.queuedDraftIds = new Set(['d2']) spyOn(TaskQueue, 'allTasks').andReturn([new SendDraftTask('d2')]) spyOn(TaskQueueStatusStore, 'waitForPerformRemote').andCallFake((task) => { task.queueState.status = Task.Status.Success return Promise.resolve(task) }) waitsForPromise(() => { return this.task.waitForSendTasks() .then(() => { expect(Array.from(this.task.queuedDraftIds)).toEqual([]) expect(this.task.failedDraftIds).toEqual([]) }) }) }); it('saves any draft ids of drafts that failed to send', () => { this.task.queuedDraftIds = new Set(['d1', 'd2']) spyOn(TaskQueue, 'allTasks').andReturn([new SendDraftTask('d1'), new SendDraftTask('d2')]) spyOn(TaskQueueStatusStore, 'waitForPerformRemote').andCallFake((task) => { if (task.draftClientId === 'd1') { task.queueState.status = Task.Status.Failed } else { task.queueState.status = Task.Status.Success } return Promise.resolve(task) }) waitsForPromise(() => { return this.task.waitForSendTasks() .then(() => { expect(Array.from(this.task.queuedDraftIds)).toEqual([]) expect(this.task.failedDraftIds).toEqual(['d1']) }) }) }); }); describe('handleError', () => { beforeEach(() => { this.baseDraft.applyPluginMetadata(PLUGIN_ID, {tableDataSource: {}}) this.d1.applyPluginMetadata(PLUGIN_ID, {rowIdx: 0}) this.d2.applyPluginMetadata(PLUGIN_ID, {rowIdx: 1}) this.baseSession = { draft: () => { return this.baseDraft }, changes: { addPluginMetadata: jasmine.createSpy('addPluginMetadata'), commit() { return Promise.resolve() }, }, } this.task.failedDraftIds = ['d1', 'd2'] spyOn(Actions, 'destroyDraft') spyOn(Actions, 'composePopoutDraft') spyOn(DraftStore, 'sessionForClientId').andReturn(Promise.resolve(this.baseSession)) jasmine.unspy(DatabaseStore, 'modelify') spyOn(DatabaseStore, 'modelify').andReturn(Promise.resolve([this.d1, this.d2])) }); it('correctly saves the failed rowIdxs to the base draft metadata', () => { waitsForPromise(() => { return this.task.handleError({message: 'Error!'}) .then((status) => { expect(status[0]).toBe(Task.Status.Failed) expect(DatabaseStore.modelify).toHaveBeenCalledWith(Message, this.task.failedDraftIds) expect(this.baseSession.changes.addPluginMetadata).toHaveBeenCalledWith(PLUGIN_ID, { tableDataSource: {}, failedDraftRowIdxs: [0, 1], }) }) }) }); it('correctly destroys failed drafts', () => { waitsForPromise(() => { return this.task.handleError({message: 'Error!'}) .then((status) => { expect(status[0]).toBe(Task.Status.Failed) expect(Actions.destroyDraft.calls.length).toBe(2) expect(Actions.destroyDraft.calls[0].args).toEqual(['d1']) expect(Actions.destroyDraft.calls[1].args).toEqual(['d2']) }) }) }); it('correctly pops out base composer with error msg', () => { waitsForPromise(() => { return this.task.handleError({message: 'Error!'}) .then((status) => { expect(status[0]).toBe(Task.Status.Failed) expect(Actions.composePopoutDraft).toHaveBeenCalledWith('baseId', { errorMessage: 'Error!', }) }) }) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/table-state-reducers-spec.es6 ================================================ import { initialState, fromJSON, toJSON, clearTableData, loadTableData, addColumn, removeLastColumn, addRow, removeRow, updateCell, } from '../lib/table-state-reducers' import {testData, testDataSource} from './fixtures' describe('TableStateReducers', function describeBlock() { describe('initialState', () => { it('returns correct initial state when there is saved state', () => { const savedState = {tableDataSource: testDataSource} expect(initialState(savedState)).toEqual(savedState) }); it('keeps only rowIdxs that failed if failedRowIdxs present in saved state', () => { const savedState = {tableDataSource: testDataSource, failedDraftRowIdxs: [1]} const {tableDataSource} = initialState(savedState) expect(tableDataSource.rows()).toEqual([testDataSource.rowAt(1)]) }); }); describe('fromJSON', () => { it('returns correct data source from json table data', () => { const {tableDataSource} = fromJSON({tableDataSource: testData}) expect(tableDataSource.toJSON()).toEqual(testData) }); }); describe('toJSON', () => { it('returns correct json object from data source', () => { const {tableDataSource} = toJSON({tableDataSource: testDataSource}) expect(tableDataSource).toEqual(testData) }); }); describe('clearTableData', () => { it('clears all data correcltly', () => { const {tableDataSource} = clearTableData({tableDataSource: testDataSource}) expect(tableDataSource.toJSON()).toEqual({ columns: [], rows: [[]], }) }); }); describe('loadTableData', () => { it('loads table data correctly', () => { const newTableData = { columns: ['my-col'], rows: [['my-val']], } const {tableDataSource} = loadTableData({tableDataSource: testDataSource}, {newTableData}) expect(tableDataSource.toJSON()).toEqual(newTableData) }); it('returns initial state if new table data is empty', () => { const newTableData = { columns: [], rows: [[]], } const {tableDataSource} = loadTableData({tableDataSource: testDataSource}, {newTableData}) expect(tableDataSource.toJSON()).toEqual(initialState().tableDataSource.toJSON()) }); }); describe('addColumn', () => { it('pushes a new column to the data source\'s columns', () => { const {tableDataSource} = addColumn({tableDataSource: testDataSource}) expect(tableDataSource.columns()).toEqual(['name', 'email', null]) }); it('pushes a new column to every row', () => { const {tableDataSource} = addColumn({tableDataSource: testDataSource}) expect(tableDataSource.rows()).toEqual([ ['donald', 'donald@nylas.com', null], ['hilary', 'hilary@nylas.com', null], ]) }); }); describe('removeLastColumn', () => { it('removes last column from the data source\'s columns', () => { const {tableDataSource} = removeLastColumn({tableDataSource: testDataSource}) expect(tableDataSource.columns()).toEqual(['name']) }); it('removes last column from every row', () => { const {tableDataSource} = removeLastColumn({tableDataSource: testDataSource}) expect(tableDataSource.rows()).toEqual([['donald'], ['hilary']]) }); }); describe('addRow', () => { it('does nothing if MAX_ROWS reached', () => { const {tableDataSource} = addRow({tableDataSource: testDataSource}, {maxRows: 2}) expect(tableDataSource).toBe(testDataSource) }); it('pushes an empty row with correct number of columns', () => { const {tableDataSource} = addRow({tableDataSource: testDataSource}, {maxRows: 3}) expect(tableDataSource.rows()).toEqual([ ['donald', 'donald@nylas.com'], ['hilary', 'hilary@nylas.com'], [null, null], ]) }); }); describe('removeRow', () => { it('removes last row', () => { const {tableDataSource} = removeRow({tableDataSource: testDataSource}) expect(tableDataSource.rows()).toEqual([['donald', 'donald@nylas.com']]) }); }); describe('updateCell', () => { it('updates cell value correctly when updating a cell that is /not/ a header', () => { const {tableDataSource} = updateCell({tableDataSource: testDataSource}, { rowIdx: 0, colIdx: 0, isHeader: false, value: 'new-val', }) expect(tableDataSource.rows()).toEqual([ ['new-val', 'donald@nylas.com'], ['hilary', 'hilary@nylas.com'], ]) }); it('updates cell value correctly when updating a cell that /is/ a header', () => { const {tableDataSource} = updateCell({tableDataSource: testDataSource}, { rowIdx: null, colIdx: 0, isHeader: true, value: 'new-val', }) expect(tableDataSource.columns()).toEqual(['new-val', 'email']) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/token-state-reducers-spec.es6 ================================================ import {Contact} from 'nylas-exports' import { toDraftChanges, toJSON, initialState, loadTableData, linkToDraft, unlinkFromDraft, removeLastColumn, updateCell, } from '../lib/token-state-reducers' import {testState, testTokenDataSource, testData} from './fixtures' describe('WorkspaceStateReducers', function describeBlock() { describe('toDraftChanges', () => { it('returns an object with participant fields populated with the correct Contact objects', () => { const {to, bcc} = toDraftChanges({}, testState) expect(to.length).toBe(1) expect(bcc.length).toBe(1) const toContact = to[0] const bccContact = bcc[0] expect(toContact instanceof Contact).toBe(true) expect(toContact.email).toEqual('hilary') expect(bccContact instanceof Contact).toEqual(true) expect(bccContact.email).toEqual('hilary@nylas.com') }); }); describe('toJSON', () => { it('only saves linked fields to json', () => { expect(toJSON(testState)).toEqual({ tokenDataSource: [ {field: 'to', colName: 'name', colIdx: 0, tokenId: 'name-0'}, {field: 'bcc', colName: 'email', colIdx: 1, tokenId: 'email-1'}, ], }) }); }); describe('initialState', () => { it('loads saved linked fields correctly when provided', () => { expect(initialState({tokenDataSource: testTokenDataSource})).toEqual({ tokenDataSource: testTokenDataSource, }) }); }); describe('loadTableData', () => { describe('when newTableData contains columns that have already been linked in the prev tableData', () => { it(`preserves the linked fields for the old columns that are still present and update the index to the new value in newTableData`, () => { const newTableData = { columns: ['email', 'other'], rows: [ ['donald@nylas.com', 'd'], ['john@gmail.com', 'j'], ], } const nextState = loadTableData(testState, {newTableData, prevColumns: testData.columns}) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'bcc', colName: 'email', colIdx: 0, tokenId: 'email-1'}, ]) }); }); describe('when newTableData only contains new columns', () => { it('unlinks all fields that are no longer present ', () => { const newTableData = { columns: ['other1'], rows: [ ['donald@nylas.com'], ['john@gmail.com'], ], } const nextState = loadTableData(testState, {newTableData, prevColumns: testData.columns}) expect(nextState.tokenDataSource.toJSON()).toEqual([]) }); }); }); describe('linkToDraft', () => { it('adds the new field correctly to tokenDataSource state', () => { const nextState = linkToDraft(testState, { colIdx: 1, colName: 'email', field: 'body', name: 'some', tokenId: 'email-2', }) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'to', colName: 'name', colIdx: 0, tokenId: 'name-0'}, {field: 'bcc', colName: 'email', colIdx: 1, tokenId: 'email-1'}, {field: 'body', colName: 'email', colIdx: 1, tokenId: 'email-2', name: 'some'}, ]) // Check that object ref is updated expect(testTokenDataSource).not.toBe(nextState.tokenDataSource) }); it('adds a new link if column has already been linked to that field', () => { const nextState = linkToDraft(testState, { colIdx: 1, colName: 'email', field: 'bcc', name: 'some', tokenId: 'email-2', }) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'to', colName: 'name', colIdx: 0, tokenId: 'name-0'}, {field: 'bcc', colName: 'email', colIdx: 1, tokenId: 'email-1'}, {field: 'bcc', colName: 'email', colIdx: 1, tokenId: 'email-2', name: 'some'}, ]) }); }); describe('unlinkFromDraft', () => { it('removes field correctly from tokenDataSource state', () => { const nextState = unlinkFromDraft(testState, {field: 'bcc', tokenId: 'email-1'}) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'to', colName: 'name', colIdx: 0, tokenId: 'name-0'}, ]) // Check that object ref is updated expect(testTokenDataSource).not.toBe(nextState.tokenDataSource) }); }); describe('removeLastColumn', () => { it('removes any tokenDataSource that were associated with the removed column', () => { const nextState = removeLastColumn(testState) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'to', colName: 'name', colIdx: 0, tokenId: 'name-0'}, ]) }); }); describe('updateCell', () => { it('updates tokenDataSource when a column name (header cell) is updated', () => { const nextState = updateCell(testState, {colIdx: 0, isHeader: true, value: 'nombre'}) expect(nextState.tokenDataSource.toJSON()).toEqual([ {field: 'to', colName: 'nombre', colIdx: 0, tokenId: 'name-0'}, {field: 'bcc', colName: 'email', colIdx: 1, tokenId: 'email-1'}, ]) }); it('does not update tokens state otherwise', () => { const nextState = updateCell(testState, {colIdx: 0, isHeader: false, value: 'nombre'}) expect(nextState.tokenDataSource).toBe(testTokenDataSource) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/spec/workspace-state-reducers-spec.es6 ================================================ import { initialState, toggleWorkspace, } from '../lib/workspace-state-reducers' import {testState} from './fixtures' describe('WorkspaceStateReducers', function describeBlock() { describe('initialState', () => { it('always opens the workspace if there is saved data', () => { expect(initialState(testState)).toEqual({ isWorkspaceOpen: true, }) }); it('defaults to closed', () => { expect(initialState()).toEqual({ isWorkspaceOpen: false, }) }); }); describe('toggleWorkspace', () => { it('toggles workspace worrectly', () => { expect(toggleWorkspace({isWorkspaceOpen: false})).toEqual({isWorkspaceOpen: true}) expect(toggleWorkspace({isWorkspaceOpen: true})).toEqual({isWorkspaceOpen: false}) }); }); }); ================================================ FILE: packages/client-app/internal_packages/composer-mail-merge/stylesheets/mail-merge.less ================================================ @import 'ui-variables'; .mail-merge-workspace { width: 100%; height: 250px; z-index: 1; border-top: 1px solid lightgrey; padding: @padding-large-vertical * 1.2 @padding-large-horizontal * 1.2; .selection-controls { display: flex; align-items: center; color: @text-color-very-subtle; margin-bottom: @padding-small-horizontal; .btn.btn-group { padding: 0; &:active { background: initial; } } .btn { display: flex; align-items: center; height: 1.5em; margin-right: 5px; color: @text-color-very-subtle; &:hover { img { background-color: @text-color-subtle; } } .btn-prev,.btn-next { height: 100%; width: 15px; img { background-color: @text-color-very-subtle; } &:active { background: darken(@btn-default-bg-color, 9%); } } .btn-prev img { transform: rotate(90deg) translate(-9px, -8px); } .btn-next img { transform: rotate(-90deg) translate(9px, 8px); } } } .mail-merge-table { height: 90%; .editable-table-container { width: 100%; &>.key-commands-region { width: initial; } } .nylas-table.editable-table { max-width: 700px; font-size: 0.9em; .table-row-header { &.selected, th, th.selected { background: initial; border: 1px solid lighten(@border-color-secondary, 5%); } } .table-row.table-row-header { height: 35px; } .table-row { height: 30px; } .numbered-cell { width: 30px; } th.table-cell { .mail-merge-token { input { cursor: -webkit-grab; } } } td.table-cell input { cursor: default; } .table-cell:not(.numbered-cell) { width: 120px; } .header-cell { display: flex; align-items: center; height: 28px; padding-left: 6px; } } } } .generate-token-colors(@n, @i: 0) when (@i =< @n) { @base-color: hsla(197 + (@i * 20), 58%, 95%, 1); @text-color: darken(desaturate(@base-color, 28%), 49%); @border-color: darken(@base-color, 8%); .token-color-@{i}.mail-merge-token { background-color: @base-color; color: @text-color; border-color: darken(@base-color, 8%); img { background-color: @text-color; } } .mail-merge-participants-text-field { .token.token-color-@{i} { &.selected,&.dragging { border-color: @text-color; } } } .generate-token-colors(@n, (@i + 1)); } .generate-token-colors(4); .mail-merge-token { border: 1px solid; border-radius: 5px; padding-left: 7px; cursor: -webkit-grab; } .mail-merge-token-wrap, .n1-overlaid-component-anchor-container.mail-merge-token-wrap { margin: 0 1px; vertical-align: bottom; .mail-merge-token { padding: @padding-small-vertical * 0.5 @padding-small-horizontal * 0.5; padding-right: 2px; img { margin-right: 10px; } } } .header-cell .mail-merge-token { display: flex; align-items: center; height: 22px; input { max-width: 90%; text-align: left; height: 100%; line-height: 100%; color: inherit; padding-bottom: 2px; } } .mail-merge-participants-text-field { .token { box-shadow: none; padding: 0; border-radius: 5px; .mail-merge-token { display: flex; align-items: center; padding: 0 @padding-base-vertical; font-size: 0.9em; img { margin-right: 10px; } } &.selected, &.dragging { background: none; border-radius: 5px; } } } .mail-merge-subject-overlaid { .toggle-preview { top: 2px; right: 22px; } } .mail-merge-subject-text-field { div[contenteditable] { line-height: 21px; font-weight: 400; padding: 13px 0 9px 0; min-width: 5em; background-color: transparent; border: none; margin: 0; &:empty:before { content: attr(placeholder); color: @text-color-very-subtle; } } } ================================================ FILE: packages/client-app/internal_packages/composer-markdown/README.md ================================================ # N1 Markdown Composer A plugin for N1 that allows you to compose emails using markdown. ![Markdown Screenshot Editor](/assets/markdown_screenshot_edit.png?raw=true "Markdown Composer Editor") ![Markdown Screenshot Preview](/assets/markdown_screenshot_preview.png?raw=true "Markdown Composer Preview") ## Install this plugin: 1. Download and run N1 2. Clone this repository (Make sure you have `git` installed and available in your system path) 3. From the menu, select `Developer > Install a Package Manually...` From the dialog, choose the directory of this plugin to install it! > When you install packages, they're moved to `~/.nylas-mail/packages`, > and N1 runs `apm install` on the command line to fetch dependencies > listed in the package's `package.json` ## Usage Just write emails using markdown. ================================================ FILE: packages/client-app/internal_packages/composer-markdown/lib/main.cjsx ================================================ # Markdown Editor # Last Revised: April 23, 2015 by Ben Gotow # # Markdown editor is a simple React component that allows you to type your # emails in markdown and see the live preview of your email in html # {ExtensionRegistry, ComponentRegistry} = require 'nylas-exports' MarkdownEditor = require './markdown-editor' MarkdownComposerExtension = require './markdown-composer-extension' module.exports = activate: -> ComponentRegistry.register MarkdownEditor, role: 'Composer:Editor' ExtensionRegistry.Composer.register(MarkdownComposerExtension) serialize: -> deactivate: -> ComponentRegistry.unregister(MarkdownEditor) ExtensionRegistry.Composer.unregister(MarkdownComposerExtension) ================================================ FILE: packages/client-app/internal_packages/composer-markdown/lib/markdown-composer-extension.coffee ================================================ marked = require 'marked' Utils = require './utils' {ComposerExtension} = require 'nylas-exports' rawBodies = {} class MarkdownComposerExtension extends ComposerExtension @applyTransformsForSending: ({draftBodyRootNode, draft}) -> rawBodies[draft.clientId] = draftBodyRootNode.innerHTML draftBodyRootNode.innerHTML = marked(draftBodyRootNode.innerText) @unapplyTransformsForSending: ({draftBodyRootNode, draft}) -> if rawBodies[draft.clientId] draftBodyRootNode.innerHTML = rawBodies[draft.clientId] module.exports = MarkdownComposerExtension ================================================ FILE: packages/client-app/internal_packages/composer-markdown/lib/markdown-editor.cjsx ================================================ Utils = require './utils' SimpleMDE = require 'simplemde' {React, ReactDOM, QuotedHTMLTransformer} = require 'nylas-exports' # Keep a file-scope variable containing the contents of the markdown stylesheet. # This will be embedded in the markdown preview iFrame, as well as the email body. # The stylesheet is loaded when a preview component is first mounted. markdownStylesheet = null splitContents = (contents) -> quoteStart = contents.search(/(
@mde = new SimpleMDE( inputStyle: 'contenteditable' element: ReactDOM.findDOMNode(@refs.container), hideIcons: ['fullscreen', 'side-by-side'] showIcons: ['code', 'table'] spellChecker: false, ) @mde.codemirror.on("change", @_onBodyChanged) @mde.codemirror.on("keydown", @_onKeyDown) @setCurrentBodyInDOM() componentDidUpdate: (prevProps) => wasEmpty = prevProps.body.length is 0 if @props.body isnt prevProps.body and @props.body isnt @currentBodyInDOM() @setCurrentBodyInDOM() if wasEmpty @mde.codemirror.execCommand('goDocEnd') focus: => @mde.codemirror.focus() focusAbsoluteEnd: => @focus() @mde.codemirror.execCommand('goDocEnd') setCurrentBodyInDOM: => [editable, uneditable] = splitContents(@props.body) uneditableEl = ReactDOM.findDOMNode(@refs.uneditable) uneditableEl.innerHTML = uneditable uneditableNoticeEl = ReactDOM.findDOMNode(@refs.uneditableNotice) if Utils.getTextFromHtml(uneditable).length > 0 uneditableNoticeEl.style.display = 'block' else uneditableNoticeEl.style.display = 'none' @mde.value(Utils.getTextFromHtml(editable)) currentBodyInDOM: => uneditableEl = ReactDOM.findDOMNode(@refs.uneditable) return @mde.value() + uneditableEl.innerHTML getCurrentSelection: -> getPreviousSelection: -> setSelection: -> container = ReactDOM.findDOMNode(@refs.container) sel = document.getSelection() sel.setBaseAndExtent(container, 0, container, 0) _onDOMMutated: -> _onBodyChanged: => setImmediate => value = @currentBodyInDOM() @props.onBodyChanged({target: {value}}) _onKeyDown: (codemirror, e)=> if e.key is 'Tab' and e.shiftKey is true position = codemirror.cursorCoords(true, 'local') isAtBeginning = position.top <= 5 and position.left <= 5 if isAtBeginning # TODO i'm /really/ sorry # Subject is at position 2 within the tab group, the focused text area # in this component is at position 17, so that's why we shift back 15 # positions. # This will break if the dom elements between here and the subject ever # change @context.parentTabGroup.shiftFocus(-15) e.preventDefault() e.codemirrorIgnore = true render: -> # TODO sorry # Add style tag to disable incompatible plugins
The markdown editor does not support editing signatures or quoted text. Content below will be included in your message.
module.exports = MarkdownEditor ================================================ FILE: packages/client-app/internal_packages/composer-markdown/lib/utils.coffee ================================================ class Utils @getTextFromHtml: (html) -> div = document.createElement('div') div.innerHTML = html div.textContent ? div.innerText module.exports = Utils ================================================ FILE: packages/client-app/internal_packages/composer-markdown/package.json ================================================ { "name": "composer-markdown", "version": "0.1.0", "main": "./lib/main", "title": "Markdown (Experimental)", "description": "Write emails using Markdown!", "isHiddenOnPluginsPage": true, "license": "GPL-3.0", "icon": "./icon.png", "engines": { "nylas": "*" }, "isOptional": true, "repository": { "type": "git", "url": "" }, "windowTypes": { "default": true, "composer": true, "thread-popout": true } } ================================================ FILE: packages/client-app/internal_packages/composer-markdown/stylesheets/index.less ================================================ @import "../internal_packages/composer-markdown/node_modules/simplemde/dist/simplemde.min.css"; @import "ui-variables"; @import "ui-mixins"; @blurred-primary-color: mix(@background-primary, #ffbb00, 96%); .compose-body .markdown-editor { margin: auto; padding: 10px 23px 10px; width: 100%; .editing-region div[contenteditable] { min-height: 0; padding: 0; } .uneditable-notice { text-align: center; font-size: 0.9em; color: @text-color-very-subtle; margin-bottom: 10px; border-top: 1px dashed; border-bottom: 1px dashed; padding: 4px; } } .CodeMirror { height: 225px; min-height: 225px; background: transparent; } .CodeMirror-sided { display: inline-block; } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/README.md ================================================ # QuickSchedule Say goodbye to the hassle of scheduling! This new plugin lets you avoid the typical back-and-forth of picking a time to meet. Just select a few options, and your recipient confirms with one click. It's the best way to instantly schedule meetings. This plugin works by adding a small "Schedule" button next to the Send button in the composer. Clicking the button will prompt the creation of a quick event creator. You can even select a set of proposed times. When you do this a calendar pops up with your availability. You can then select some proposed times for the receipient to choose from. #### Enable this plugin 1. Download and run N1 2. Navigate to Preferences > Plugins and click "Enable" beside the plugin. #### Who is this for? Anyone who makes a lot of appointments! If you are a developer, this is also a great example of a more complicated plugin that requires a backend service, and demonstrates how arbitrary JavaScript can be inserted to create custom functionality. ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/calendar/proposed-time-calendar-data-source.es6 ================================================ import {Rx, CalendarDataSource} from 'nylas-exports' import ProposedTimeCalendarStore from '../proposed-time-calendar-store' export default class ProposedTimeCalendarDataSource extends CalendarDataSource { buildObservable({startTime, endTime, disabledCalendars}) { this.observable = Rx.Observable.combineLatest([ super.buildObservable({startTime, endTime, disabledCalendars}), Rx.Observable.fromStore(ProposedTimeCalendarStore).map((store) => store.proposalsAsEvents()), ]) .map(([superResult, proposedTimes]) => { return {events: superResult.events.concat(proposedTimes)} }) return this.observable; } } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/calendar/proposed-time-event.jsx ================================================ import React from 'react' import classnames from 'classnames' import SchedulerActions from '../scheduler-actions' import {CALENDAR_ID} from '../scheduler-constants' /** * Gets rendered in a CalendarEvent */ export default class ProposedTimeEvent extends React.Component { static displayName = "ProposedTimeEvent"; static propTypes = { event: React.PropTypes.object, } // Since ProposedTimeEvent is part of an Injected Component set, by // default it's placed in its own container that's rendered separately. // // This makes two separate React trees which cause the react event // propagations to be separate. See: // https://github.com/facebook/react/issues/1691 // // Unfortunately, this means that `stopPropagation` doesn't work from // within injected component sets unless the `containerRequired` is set // to `false` static containerRequired = false; _onMouseDown(event) { event.stopPropagation(); SchedulerActions.removeProposedTime(event.target.dataset); } render() { const className = classnames({ "rm-time": true, "proposal": this.props.event.proposalType === "proposal", "availability": this.props.event.proposalType === "availability", }); if (this.props.event.calendarId === CALENDAR_ID) { return (
×
) } return false } } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/calendar/proposed-time-picker.jsx ================================================ import React from 'react' import {Utils} from 'nylas-exports' import {NylasCalendar} from 'nylas-component-kit' import SchedulerActions from '../scheduler-actions' import ProposedTimeCalendarStore from '../proposed-time-calendar-store' import ProposedTimeCalendarDataSource from './proposed-time-calendar-data-source' /** * A an extended NylasCalendar that lets you pick proposed times. */ export default class ProposedTimePicker extends React.Component { static displayName = "ProposedTimePicker"; static containerStyles = { height: "100%", } constructor(props) { super(props); this.state = { proposals: ProposedTimeCalendarStore.proposals(), duration: ProposedTimeCalendarStore.currentDuration(), pendingSave: ProposedTimeCalendarStore.pendingSave(), } } componentDidMount() { this._usub = ProposedTimeCalendarStore.listen(() => { this.setState({ duration: ProposedTimeCalendarStore.currentDuration(), proposals: ProposedTimeCalendarStore.proposals(), pendingSave: ProposedTimeCalendarStore.pendingSave(), }); }) NylasEnv.displayWindow() } shouldComponentUpdate(nextProps, nextState) { return (!Utils.isEqualReact(nextProps, this.props) || !Utils.isEqualReact(nextState, this.state)); } componentWillUnmount() { this._usub() } _dataSource() { return new ProposedTimeCalendarDataSource() } _bannerComponents = () => { return { week: "Click and drag to propose times.", } } _footerComponents = () => { return { week: [this._leftFooterComponents(), this._rightFooterComponents()], } } _renderClearButton() { if (this.state.proposals.length === 0) { return false } return ( ) } _onClearProposals = () => { SchedulerActions.clearProposals() } _leftFooterComponents() { const optComponents = ProposedTimeCalendarStore.DURATIONS.map((opt, i) => ) const durationPicker = (
) return ([durationPicker, this._renderClearButton()]); } _rightFooterComponents() { return ( ); } _onChangeDuration = (event) => { SchedulerActions.changeDuration(event.target.value.split("|")) } _onDone = () => { const proposals = ProposedTimeCalendarStore.proposals(); // NOTE: This gets dispatched to the main window const {draftClientId} = NylasEnv.getWindowProps() SchedulerActions.confirmChoices({proposals, draftClientId}); // Make sure the action gets to the main window then close this one. setTimeout(() => { NylasEnv.close() }, 10) } _onCalendarMouseUp({time, currentView}) { if (currentView !== NylasCalendar.WEEK_VIEW) { return } if (time) { SchedulerActions.addToProposedTimeBlock(time); } SchedulerActions.endProposedTimeBlock(); return } _onCalendarMouseMove({time, mouseIsDown, currentView}) { if (!time || !mouseIsDown || currentView !== NylasCalendar.WEEK_VIEW) { return } SchedulerActions.addToProposedTimeBlock(time); return } _onCalendarMouseDown({time, currentView}) { if (!time || currentView !== NylasCalendar.WEEK_VIEW) { return } SchedulerActions.startProposedTimeBlock(time); return } render() { return ( ) } } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/email-b64-images.es6 ================================================ export const b64Images = { location: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTVFNzg0RkNFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTVFNzg0RkRFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3RkVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA4MEVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkDmWKcAAAFpSURBVHjahNNPKERRFMfxNzNK+RMrFhYSpWzobbHQrFBiIwspkdEsRBaUHSsbUhbIgkgaWVkqlCSpiVmJmqJsiTJIGt+r36vrzZuc+tR999175tx73oSy2axjIplMOopqjKEZHwjDLNrFOr7MItd1fxcXOH+jBfu4wzLOUYJOTKMDA3j2NtgJarGHHUz4El9jBYfYRB8yjsrzYgppa3M5hjGEMjyhBw2IBlVgDrWocUS/2K7zt6n0B5yhFwf+Cl5xo3EcrahBvRLE9O4eFd4mO8EnSq1xSCJa9653xXgLOoIZN+IEa2rnpZKY9m1oXaXuKidBWr1f0vMMErqDlOYK1a1E0BFM/5tQ5WtfynqO65hXQQku8IgFJ38MYlvdyEnwgll0oTtgs7mHImzZk2HfomPMYxV11nxMH9SIqsybwMQcTnGk56g+qklrzgnqghff6FfJGfV/3OrOvwkc/Y1H1dpbXVxg/AgwALwFT41l/QPcAAAAAElFTkSuQmCC`, description: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzJFN0IwN0RFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzJFN0IwN0VFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3QkVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA3Q0VENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpVUSsoAAABkSURBVHjaYvz//z8DJYBx1AAGliNHjsQAaW4g/kWiXk4gfsECJAKBWASIv5JogCAQXwYZEAXyChDj8wsjDrF/IAN+UhQGQIwvDBihcjuB+BYuA/CFARNU7hYuA0ZTIhUMAAgwABS7Llh6+cz5AAAAAElFTkSuQmCC`, time: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzJFN0IwNzlFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzJFN0IwN0FFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3N0VENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA3OEVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PmHXWPIAAAIoSURBVHjaXJM7iFNBFIbn3oRkQ3ZJIEUIKrgiaLEoFoLFilupIMq2iqBgI1jYKCJooQg+EGwtBbFRRNBKrES2UAgICoKgEbFIookkhJt34vcP58plB75M7syZ/zzmTFCtVt2mcRguBkGwDIvz+XwGTdY24Ba0ksZh4n8Ab+B5GIYRh29Op9M1Dq+nUqkXrB+CH3A6KZBOCH2BDAf3MNeazabr9XpLiH0vl8sf8/n87clkcpa9x7AF7iYjeAmLsJzJZGqdTse1Wi2H9wvD4fBovV7Xf0ckj7BZgzs2e4FVOAYrGMira7fbDiGH9wVmHE+cIvJ5BsFbpnvwJBa4Dk/hbyyAV3nT/pI3CkPX7XYdNZGAlq5YxKsS2Km8ZDQajVwURS6dTvuQGQXz6lEkJqDxHk5JIAeftTKbzdx4PI6N9LMNhvqW90aj4YVt/ydsj4s4jz2Z51igBzdgr6Lq9/s+FUtvHtdgALt1UEbFYtGHqgZi/Ty8gmuIrysK1UfpMrbCr9BCOSkBpcCdu1Kp5OuB0G8OPZAQ37VsNusKhYJPh7EfngW0slr3tdViIHWlol5QuBIdDAZOhyuVisvlchK/is0l7EuBvYV3di374looHXkSuhk60efO9womn+CE0ouLeMTa84PuXunoNjQrItXFbuK4Hb5vtfnfypH1gwr3DR7CQQR2CMTOMG9Yy6uJLm9+TBpdOGCv7Zy16oLt/THPu+Br8jX+E2AAonoDF+eSc+MAAAAASUVORK5CYII=`, }; ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/email-images.json ================================================ { "location": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTVFNzg0RkNFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTVFNzg0RkRFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3RkVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA4MEVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkDmWKcAAAFpSURBVHjahNNPKERRFMfxNzNK+RMrFhYSpWzobbHQrFBiIwspkdEsRBaUHSsbUhbIgkgaWVkqlCSpiVmJmqJsiTJIGt+r36vrzZuc+tR999175tx73oSy2axjIplMOopqjKEZHwjDLNrFOr7MItd1fxcXOH+jBfu4wzLOUYJOTKMDA3j2NtgJarGHHUz4El9jBYfYRB8yjsrzYgppa3M5hjGEMjyhBw2IBlVgDrWocUS/2K7zt6n0B5yhFwf+Cl5xo3EcrahBvRLE9O4eFd4mO8EnSq1xSCJa9653xXgLOoIZN+IEa2rnpZKY9m1oXaXuKidBWr1f0vMMErqDlOYK1a1E0BFM/5tQ5WtfynqO65hXQQku8IgFJ38MYlvdyEnwgll0oTtgs7mHImzZk2HfomPMYxV11nxMH9SIqsybwMQcTnGk56g+qklrzgnqghff6FfJGfV/3OrOvwkc/Y1H1dpbXVxg/AgwALwFT41l/QPcAAAAAElFTkSuQmCC", "description": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzJFN0IwN0RFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzJFN0IwN0VFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3QkVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA3Q0VENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpVUSsoAAABkSURBVHjaYvz//z8DJYBx1AAGliNHjsQAaW4g/kWiXk4gfsECJAKBWASIv5JogCAQXwYZEAXyChDj8wsjDrF/IAN+UhQGQIwvDBihcjuB+BYuA/CFARNU7hYuA0ZTIhUMAAgwABS7Llh6+cz5AAAAAElFTkSuQmCC", "time": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzJFN0IwNzlFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzJFN0IwN0FFRDYzMTFFNTlEOUREQkE1NjlFNkRFRjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MkU3QjA3N0VENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MkU3QjA3OEVENjMxMUU1OUQ5RERCQTU2OUU2REVGMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PmHXWPIAAAIoSURBVHjaXJM7iFNBFIbn3oRkQ3ZJIEUIKrgiaLEoFoLFilupIMq2iqBgI1jYKCJooQg+EGwtBbFRRNBKrES2UAgICoKgEbFIookkhJt34vcP58plB75M7syZ/zzmTFCtVt2mcRguBkGwDIvz+XwGTdY24Ba0ksZh4n8Ab+B5GIYRh29Op9M1Dq+nUqkXrB+CH3A6KZBOCH2BDAf3MNeazabr9XpLiH0vl8sf8/n87clkcpa9x7AF7iYjeAmLsJzJZGqdTse1Wi2H9wvD4fBovV7Xf0ckj7BZgzs2e4FVOAYrGMira7fbDiGH9wVmHE+cIvJ5BsFbpnvwJBa4Dk/hbyyAV3nT/pI3CkPX7XYdNZGAlq5YxKsS2Km8ZDQajVwURS6dTvuQGQXz6lEkJqDxHk5JIAeftTKbzdx4PI6N9LMNhvqW90aj4YVt/ydsj4s4jz2Z51igBzdgr6Lq9/s+FUtvHtdgALt1UEbFYtGHqgZi/Ty8gmuIrysK1UfpMrbCr9BCOSkBpcCdu1Kp5OuB0G8OPZAQ37VsNusKhYJPh7EfngW0slr3tdViIHWlol5QuBIdDAZOhyuVisvlchK/is0l7EuBvYV3di374looHXkSuhk60efO9womn+CE0ouLeMTa84PuXunoNjQrItXFbuK4Hb5vtfnfypH1gwr3DR7CQQR2CMTOMG9Yy6uJLm9+TBpdOGCv7Zy16oLt/THPu+Br8jX+E2AAonoDF+eSc+MAAAAASUVORK5CYII=" } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/event-datetime-input.jsx ================================================ import React from 'react'; import moment from 'moment-timezone' import {DateUtils} from 'nylas-exports' function getDateFormat(type) { if (type === "date") { return "YYYY-MM-DD"; } else if (type === "time") { return "HH:mm:ss" } return null } export default class EventDatetimeInput extends React.Component { static displayName = "EventDatetimeInput"; static propTypes = { name: React.PropTypes.string, value: React.PropTypes.number.isRequired, onChange: React.PropTypes.func.isRequired, reversed: React.PropTypes.bool, }; constructor(props) { super(props); this._datePartStrings = {time: "", date: ""}; } _onDateChange() { const {date, time} = this._datePartStrings; const format = `${getDateFormat("date")} ${getDateFormat("time")}`; const newDate = moment.tz(`${date} ${time}`, format, DateUtils.timeZone).unix(); this.props.onChange(newDate) } _renderInput(type) { const unixDate = this.props.value; const str = moment.unix(unixDate).tz(DateUtils.timeZone).format(getDateFormat(type)) this._datePartStrings[type] = unixDate != null ? str : null; return ( { this._datePartStrings[type] = e.target.value; this._onDateChange() }} /> ) } render() { if (this.props.reversed) { return ( {this._renderInput("time")} on {this._renderInput("date")} ) } return ( {this._renderInput("date")} at {this._renderInput("time")} ) } } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/event-prep-helper.es6 ================================================ export const prepareEvent = (inEvent, draft, proposals = []) => { const event = inEvent if (!event.title) { event.title = ""; } event.participants = draft.participants().map((contact) => { return { name: contact.name, email: contact.email, status: "noreply", } }) if (proposals.length > 0) { event.end = null event.start = null } return event; } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/new-event-card-container.jsx ================================================ import React, {Component, PropTypes} from 'react'; import {Utils, Event} from 'nylas-exports'; import SchedulerActions from '../scheduler-actions' import NewEventCard from './new-event-card' import NewEventPreview from './new-event-preview' import {PLUGIN_ID} from '../scheduler-constants' import NewEventHelper from './new-event-helper' import RemoveEventHelper from './remove-event-helper' /** * When you're creating an event you can either be creating: * * 1. A Meeting Request with a specific start and end time * 2. OR a `pendingEvent` template that has a set of proposed times. * * Both are represented by a `pendingEvent` object on the `metadata` that * holds the JSONified representation of the `Event` * * #2 adds a set of `proposals` on the metadata object. * * This component is an OverlayedComponent. * * The SchedulerComposerExtension::_insertNewEventCard will call * `EditorAPI::insert`. We pass `insert` a React element. Under the hood, * the `` wrapper will actually place an "anchor" tag * and absolutely position our element over that anchor tag. * * This component is also decorated with the `InflatesDraftClientId` * decorator. The former is necessary for OverlaidComponents to work. The * latter provides us with up-to-date `draft` and `session` props by * inflating a `draftClientId`. * * If the Anchor is deleted, or cut, then the `` * element will unmount the `NewEventCardContainer`. * * If the anchor re-appears (via paste or some other mechanism), then this * component will be re-mounted. * * We use the mounting and unmounting of this component as signals to add or * remove the metadata on the draft. */ export default class NewEventCardContainer extends Component { static displayName = 'NewEventCardContainer'; static propTypes = { draft: PropTypes.object.isRequired, session: PropTypes.object.isRequired, style: PropTypes.object, isPreview: PropTypes.bool, } componentDidMount() { this._unlisten = SchedulerActions.confirmChoices.listen(::this._onConfirmChoices); NewEventHelper.restoreOrCreateEvent(this.props.session) } componentWillUnmount() { if (this._unlisten) { this._unlisten(); } RemoveEventHelper.hideEventData(this.props.session) } _onConfirmChoices({proposals = [], draftClientId}) { const {draft} = this.props; if (draft.clientId !== draftClientId) { return; } const metadata = draft.metadataForPluginId(PLUGIN_ID) || {}; if (proposals.length === 0) { delete metadata.proposals; } else { metadata.proposals = proposals; } this.props.session.changes.addPluginMetadata(PLUGIN_ID, metadata); } _getEvent() { const metadata = this.props.draft.metadataForPluginId(PLUGIN_ID); if (metadata && metadata.pendingEvent) { return new Event().fromJSON(metadata.pendingEvent || {}); } return null } _updateEvent = (newData) => { const {draft, session} = this.props; const newEvent = Object.assign(this._getEvent().clone(), newData); const newEventJSON = newEvent.toJSON(); const metadata = draft.metadataForPluginId(PLUGIN_ID); if (!Utils.isEqual(metadata.pendingEvent, newEventJSON)) { metadata.pendingEvent = newEventJSON; session.changes.addPluginMetadata(PLUGIN_ID, metadata); } } _removeEvent = () => { // This will delete the metadata, but it won't remove the anchor from // the contenteditable. We also need to remove the event card. RemoveEventHelper.deleteEventData(this.props.session); SchedulerActions.removeEventCard(); } render() { const {style, isPreview} = this.props; const event = this._getEvent(); let card = false; if (isPreview) { return } if (event) { card = ( {}} /> ) } return (
{card}
) } } ================================================ FILE: packages/client-app/internal_packages/composer-scheduler/lib/composer/new-event-card.jsx ================================================ import React from 'react'; import moment from 'moment-timezone' import { RetinaImg, DatePicker, TimePicker, TabGroupRegion, } from 'nylas-component-kit' import { DateUtils, Calendar, AccountStore, DatabaseStore} from 'nylas-exports'; import {PLUGIN_ID} from '../scheduler-constants' import NewEventHelper from './new-event-helper' import ProposedTimeList from './proposed-time-list' export default class NewEventCard extends React.Component { static displayName = 'NewEventCard'; static propTypes = { event: React.PropTypes.object.isRequired, draft: React.PropTypes.object.isRequired, onChange: React.PropTypes.func.isRequired, onRemove: React.PropTypes.func.isRequired, onParticipantsClick: React.PropTypes.func.isRequired, }; constructor(props) { super(props); this._mounted = false; this.state = { calendars: [], }; } componentDidMount() { this._mounted = true; const email = this.props.draft.from[0].email this._loadCalendarsForEmail(email); } componentWillReceiveProps(newProps) { const email = newProps.draft.from[0].email this._loadCalendarsForEmail(email); } componentWillUnmount() { this._mounted = false; } _loadCalendarsForEmail(email) { if (this._lastEmail === email) { return } this._lastEmail = email const account = AccountStore.accountForEmail(email); DatabaseStore.findAll(Calendar, {accountId: account.id}) .then((calendars) => { if (!this._mounted || !calendars) { return } this.setState({calendars: calendars.filter(c => !c.readOnly)}) }); } _renderIcon(name) { return ( ) } _renderParticipants() { return this.props.draft.participants().map(r => r.displayName()).join(", ") } _renderCalendarPicker() { if (this.state.calendars.length <= 1) { return false; } const calOpts = this.state.calendars.map(cal => ); const onChange = (e) => { this.props.onChange({calendarId: e.target.value}) } return (
{this._renderIcon("ic-eventcard-calendar@2x.png")}
) } _onProposeTimes = () => { NewEventHelper.launchCalendarWindow(this.props.draft.clientId); } _eventStart() { return moment.unix(this.props.event.start || moment().unix()) } _eventEnd() { return moment.unix(this.props.event.end || moment().unix()) } _onChangeDay = (newTimestamp) => { const newDay = moment(newTimestamp) const start = this._eventStart() const end = this._eventEnd() start.year(newDay.year()) end.year(newDay.year()) start.dayOfYear(newDay.dayOfYear()) end.dayOfYear(newDay.dayOfYear()) this.props.onChange({start: start.unix(), end: end.unix()}) } _onChangeStartTime = (newTimestamp) => { const newTime = moment(newTimestamp) const start = this._eventStart() const end = this._eventEnd() start.hour(newTime.hour()) start.minute(newTime.minute()) let newEnd = moment(end) if (end.isSameOrBefore(start)) { const leftInDay = moment(start).endOf('day').diff(start) const move = Math.min(leftInDay, moment.duration(1, 'hour').asMilliseconds()); newEnd = moment(start).add(move, 'ms') } this.props.onChange({start: start.unix(), end: newEnd.unix()}) } _onChangeEndTime = (newTimestamp) => { const newTime = moment(newTimestamp) const start = this._eventStart() const end = this._eventEnd() end.hour(newTime.hour()) end.minute(newTime.minute()) let newStart = moment(start) if (start.isSameOrAfter(end)) { const sinceDay = end.diff(moment(end).startOf('day')) const move = Math.min(sinceDay, moment.duration(1, 'hour').asMilliseconds()); newStart = moment(end).subtract(move, 'ms'); } this.props.onChange({end: end.unix(), start: newStart.unix()}) } _renderTimePicker() { const metadata = this.props.draft.metadataForPluginId(PLUGIN_ID); if (metadata && metadata.proposals) { return ( ) } const startVal = (this.props.event.start) * 1000; const endVal = (this.props.event.end) * 1000; return (
{this._renderIcon("ic-eventcard-time@2x.png")} to {moment().tz(DateUtils.timeZone).format("z")}   on  
) } _renderSuggestPrompt() { const metadata = this.props.draft.metadataForPluginId(PLUGIN_ID); if (metadata && metadata.proposals) { return ( ) } return ( ) } render() { return (
{this._renderIcon("ic-eventcard-description@2x.png")} this.props.onChange({title: e.target.value})} />
{this._renderTimePicker()} {this._renderSuggestPrompt()} {this._renderCalendarPicker()}
{this._renderIcon("ic-eventcard-people@2x.png")}
{this._renderParticipants()}
{this._renderIcon("ic-eventcard-location@2x.png")} this.props.onChange({location: e.target.value})} />
{this._renderIcon("ic-eventcard-notes@2x.png")}