summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Sizov <vsv2711@gmail.com>2015-12-24 13:38:17 +0200
committerValery Sizov <vsv2711@gmail.com>2015-12-24 13:38:17 +0200
commit999a374f778909b3681190dcf0936ba9bb989413 (patch)
tree03a14e9bc34eb856a66c3a641ac1383d21a6f396
parentd794ae8e1f6351282707d45df97ac0ec2a41eeb6 (diff)
parente557c8d0a2c1b05148a9d73a8a658962a3ef6147 (diff)
downloadgitlab-ce-emoji_picker_frequently_used.tar.gz
Merge branch 'emoji-picker-search'into emoji_picker_frequently_usedemoji_picker_frequently_used
-rw-r--r--.rubocop.yml42
-rw-r--r--CHANGELOG20
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile18
-rw-r--r--Gemfile.lock86
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/application.js.coffee2
-rw-r--r--app/assets/javascripts/awards_handler.coffee36
-rw-r--r--app/assets/javascripts/issuable_context.js.coffee2
-rw-r--r--app/assets/javascripts/issue.js.coffee8
-rw-r--r--app/assets/javascripts/merge_request.js.coffee8
-rw-r--r--app/assets/stylesheets/application.scss6
-rw-r--r--app/assets/stylesheets/framework/blocks.scss2
-rw-r--r--app/assets/stylesheets/framework/buttons.scss39
-rw-r--r--app/assets/stylesheets/framework/common.scss12
-rw-r--r--app/assets/stylesheets/framework/issue_box.scss14
-rw-r--r--app/assets/stylesheets/framework/layout.scss2
-rw-r--r--app/assets/stylesheets/framework/lists.scss6
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss2
-rw-r--r--app/assets/stylesheets/framework/mixins.scss9
-rw-r--r--app/assets/stylesheets/framework/mobile.scss2
-rw-r--r--app/assets/stylesheets/framework/panels.scss5
-rw-r--r--app/assets/stylesheets/framework/timeline.scss3
-rw-r--r--app/assets/stylesheets/framework/variables.scss33
-rw-r--r--app/assets/stylesheets/pages/awards.scss8
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss33
-rw-r--r--app/assets/stylesheets/pages/emojis.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss45
-rw-r--r--app/assets/stylesheets/pages/issues.scss5
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss2
-rw-r--r--app/assets/stylesheets/pages/note_form.scss6
-rw-r--r--app/assets/stylesheets/pages/notes.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss43
-rw-r--r--app/assets/stylesheets/pages/status.scss17
-rw-r--r--app/controllers/admin/identities_controller.rb17
-rw-r--r--app/controllers/application_controller.rb15
-rw-r--r--app/controllers/ci/lints_controller.rb4
-rw-r--r--app/controllers/dashboard/snippets_controller.rb3
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb16
-rw-r--r--app/controllers/projects/merge_requests_controller.rb11
-rw-r--r--app/controllers/projects/notes_controller.rb5
-rw-r--r--app/controllers/projects/protected_branches_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb5
-rw-r--r--app/helpers/application_helper.rb10
-rw-r--r--app/helpers/button_helper.rb4
-rw-r--r--app/helpers/ci_status_helper.rb22
-rw-r--r--app/helpers/external_wiki_helper.rb2
-rw-r--r--app/helpers/gitlab_markdown_helper.rb9
-rw-r--r--app/helpers/issues_helper.rb15
-rw-r--r--app/helpers/labels_helper.rb2
-rw-r--r--app/helpers/merge_requests_helper.rb11
-rw-r--r--app/helpers/projects_helper.rb23
-rw-r--r--app/helpers/tree_helper.rb2
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/application_setting.rb16
-rw-r--r--app/models/ci/build.rb13
-rw-r--r--app/models/ci/commit.rb10
-rw-r--r--app/models/concerns/mentionable.rb18
-rw-r--r--app/models/concerns/participable.rb31
-rw-r--r--app/models/concerns/token_authenticatable.rb24
-rw-r--r--app/models/issue.rb10
-rw-r--r--app/models/jira_issue.rb2
-rw-r--r--app/models/merge_request.rb6
-rw-r--r--app/models/namespace.rb4
-rw-r--r--app/models/note.rb4
-rw-r--r--app/models/project.rb22
-rw-r--r--app/models/project_services/bamboo_service.rb6
-rw-r--r--app/models/project_services/flowdock_service.rb2
-rw-r--r--app/models/project_services/gemnasium_service.rb2
-rw-r--r--app/models/project_services/gitlab_ci_service.rb7
-rw-r--r--app/models/project_services/jira_service.rb241
-rw-r--r--app/models/project_services/teamcity_service.rb8
-rw-r--r--app/models/user.rb7
-rw-r--r--app/services/create_commit_builds_service.rb18
-rw-r--r--app/services/issues/close_service.rb5
-rw-r--r--app/services/merge_requests/refresh_service.rb2
-rw-r--r--app/services/system_note_service.rb9
-rw-r--r--app/views/admin/dashboard/index.html.haml4
-rw-r--r--app/views/admin/identities/index.html.haml1
-rw-r--r--app/views/admin/identities/new.html.haml4
-rw-r--r--app/views/admin/runners/index.html.haml2
-rw-r--r--app/views/ci/lints/_create.html.haml2
-rw-r--r--app/views/ci/lints/create.js.haml2
-rw-r--r--app/views/ci/lints/show.html.haml36
-rw-r--r--app/views/dashboard/_projects_head.html.haml27
-rw-r--r--app/views/dashboard/milestones/show.html.haml20
-rw-r--r--app/views/dashboard/projects/_projects.html.haml8
-rw-r--r--app/views/devise/mailer/unlock_instructions.html.erb7
-rw-r--r--app/views/devise/mailer/unlock_instructions.html.haml10
-rw-r--r--app/views/devise/unlocks/new.html.erb12
-rw-r--r--app/views/devise/unlocks/new.html.haml14
-rw-r--r--app/views/groups/_projects.html.haml4
-rw-r--r--app/views/groups/milestones/show.html.haml32
-rw-r--r--app/views/groups/show.html.haml78
-rw-r--r--app/views/notify/_note_message.html.haml2
-rw-r--r--app/views/projects/builds/show.html.haml4
-rw-r--r--app/views/projects/commit/_commit_box.html.haml6
-rw-r--r--app/views/projects/commit_statuses/_commit_status.html.haml8
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/issues/_closed_by_box.html.haml3
-rw-r--r--app/views/projects/issues/_discussion.html.haml7
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml7
-rw-r--r--app/views/projects/issues/show.html.haml99
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml7
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml8
-rw-r--r--app/views/projects/merge_requests/_show.html.haml135
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml12
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml13
-rw-r--r--app/views/projects/merge_requests/widget/_merged.html.haml12
-rw-r--r--app/views/projects/merge_requests/widget/open/_accept.html.haml24
-rw-r--r--app/views/projects/milestones/show.html.haml68
-rw-r--r--app/views/projects/notes/_form.html.haml2
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/tree/_tree_header.html.haml12
-rw-r--r--app/views/search/results/_issue.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml16
-rw-r--r--app/views/shared/snippets/_header.html.haml44
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/views/votes/_votes_block.html.haml11
-rw-r--r--config/gitlab.yml.example22
-rw-r--r--config/initializers/1_settings.rb15
-rw-r--r--config/initializers/carrierwave.rb10
-rw-r--r--config/initializers/devise.rb14
-rw-r--r--config/initializers/sidekiq.rb11
-rw-r--r--config/routes.rb4
-rw-r--r--config/schedule.yml10
-rw-r--r--db/migrate/20151012173029_set_jira_service_api_url.rb50
-rw-r--r--db/migrate/20151203162134_add_build_events_to_services.rb2
-rw-r--r--db/migrate/20151209144329_migrate_ci_web_hooks.rb3
-rw-r--r--db/migrate/20151210030143_add_unlock_token_to_user.rb5
-rw-r--r--db/migrate/20151210125928_add_ci_to_project.rb2
-rw-r--r--db/migrate/20151210125929_add_project_id_to_ci.rb2
-rw-r--r--db/migrate/20151210125930_migrate_ci_to_project.rb7
-rw-r--r--db/migrate/20151210125931_add_index_to_ci_tables.rb2
-rw-r--r--db/migrate/20151210125932_drop_null_for_ci_tables.rb2
-rw-r--r--db/migrate/20151224123230_rename_emojis.rb15
-rw-r--r--db/schema.rb3
-rw-r--r--doc/README.md1
-rw-r--r--doc/api/projects.md28
-rw-r--r--doc/ci/README.md1
-rw-r--r--doc/ci/docker/using_docker_images.md23
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/ci/yaml/README.md346
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/integration/README.md2
-rw-r--r--doc/integration/cas.md62
-rw-r--r--doc/integration/jira.md113
-rw-r--r--doc/integration/jira_issue_reference.pngbin0 -> 39942 bytes
-rw-r--r--doc/integration/jira_project_name.pngbin0 -> 60598 bytes
-rw-r--r--doc/integration/jira_service.pngbin0 -> 59082 bytes
-rw-r--r--doc/integration/jira_service_close_issue.pngbin0 -> 88433 bytes
-rw-r--r--doc/integration/jira_service_page.pngbin0 -> 162449 bytes
-rw-r--r--doc/integration/jira_workflow_screenshot.pngbin0 -> 121534 bytes
-rw-r--r--doc/raketasks/README.md3
-rw-r--r--doc/raketasks/check.md63
-rw-r--r--doc/raketasks/check_repos_output.pngbin0 -> 73786 bytes
-rw-r--r--doc/update/8.2-to-8.3.md22
-rw-r--r--doc/workflow/README.md1
-rw-r--r--doc/workflow/importing/README.md20
-rw-r--r--doc/workflow/importing/migrating_from_svn.md79
-rw-r--r--features/project/issues/award_emoji.feature10
-rw-r--r--features/project/issues/issues.feature6
-rw-r--r--features/project/service.feature6
-rw-r--r--features/steps/explore/groups.rb8
-rw-r--r--features/steps/explore/projects.rb12
-rw-r--r--features/steps/groups.rb2
-rw-r--r--features/steps/profile/profile.rb2
-rw-r--r--features/steps/project/forked_merge_requests.rb3
-rw-r--r--features/steps/project/issues/award_emoji.rb12
-rw-r--r--features/steps/project/issues/issues.rb10
-rw-r--r--features/steps/project/merge_requests.rb4
-rw-r--r--features/steps/project/project.rb2
-rw-r--r--features/steps/project/services.rb18
-rw-r--r--features/steps/project/snippets.rb2
-rw-r--r--features/steps/project/source/browse_files.rb12
-rw-r--r--features/steps/shared/diff_note.rb2
-rw-r--r--features/steps/shared/paths.rb8
-rw-r--r--features/steps/snippets/snippets.rb2
-rw-r--r--features/support/capybara.rb2
-rw-r--r--fixtures/emojis/aliases.json367
-rw-r--r--fixtures/emojis/index.json13376
-rw-r--r--lib/api/entities.rb3
-rw-r--r--lib/api/projects.rb15
-rw-r--r--lib/award_emoji.rb53
-rw-r--r--lib/banzai.rb13
-rw-r--r--lib/banzai/cross_project_reference.rb22
-rw-r--r--lib/banzai/filter.rb10
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb (renamed from lib/gitlab/markdown/abstract_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/autolink_filter.rb (renamed from lib/gitlab/markdown/filter/autolink_filter.rb)6
-rw-r--r--lib/banzai/filter/commit_range_reference_filter.rb (renamed from lib/gitlab/markdown/filter/commit_range_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/commit_reference_filter.rb (renamed from lib/gitlab/markdown/filter/commit_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/emoji_filter.rb (renamed from lib/gitlab/markdown/filter/emoji_filter.rb)6
-rw-r--r--lib/banzai/filter/external_issue_reference_filter.rb (renamed from lib/gitlab/markdown/filter/external_issue_reference_filter.rb)26
-rw-r--r--lib/banzai/filter/external_link_filter.rb (renamed from lib/gitlab/markdown/filter/external_link_filter.rb)6
-rw-r--r--lib/banzai/filter/issue_reference_filter.rb (renamed from lib/gitlab/markdown/filter/issue_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/label_reference_filter.rb (renamed from lib/gitlab/markdown/filter/label_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/markdown_filter.rb (renamed from lib/gitlab/markdown/filter/markdown_filter.rb)13
-rw-r--r--lib/banzai/filter/merge_request_reference_filter.rb (renamed from lib/gitlab/markdown/filter/merge_request_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/redactor_filter.rb (renamed from lib/gitlab/markdown/filter/redactor_filter.rb)8
-rw-r--r--lib/banzai/filter/reference_filter.rb (renamed from lib/gitlab/markdown/reference_filter.rb)27
-rw-r--r--lib/banzai/filter/reference_gatherer_filter.rb (renamed from lib/gitlab/markdown/filter/reference_gatherer_filter.rb)13
-rw-r--r--lib/banzai/filter/relative_link_filter.rb (renamed from lib/gitlab/markdown/filter/relative_link_filter.rb)6
-rw-r--r--lib/banzai/filter/sanitization_filter.rb (renamed from lib/gitlab/markdown/filter/sanitization_filter.rb)6
-rw-r--r--lib/banzai/filter/snippet_reference_filter.rb (renamed from lib/gitlab/markdown/filter/snippet_reference_filter.rb)6
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb (renamed from lib/gitlab/markdown/filter/syntax_highlight_filter.rb)6
-rw-r--r--lib/banzai/filter/table_of_contents_filter.rb (renamed from lib/gitlab/markdown/filter/table_of_contents_filter.rb)8
-rw-r--r--lib/banzai/filter/task_list_filter.rb (renamed from lib/gitlab/markdown/filter/task_list_filter.rb)6
-rw-r--r--lib/banzai/filter/upload_link_filter.rb (renamed from lib/gitlab/markdown/filter/upload_link_filter.rb)6
-rw-r--r--lib/banzai/filter/user_reference_filter.rb (renamed from lib/gitlab/markdown/filter/user_reference_filter.rb)6
-rw-r--r--lib/banzai/lazy_reference.rb27
-rw-r--r--lib/banzai/pipeline.rb10
-rw-r--r--lib/banzai/pipeline/asciidoc_pipeline.rb13
-rw-r--r--lib/banzai/pipeline/atom_pipeline.rb14
-rw-r--r--lib/banzai/pipeline/base_pipeline.rb30
-rw-r--r--lib/banzai/pipeline/combined_pipeline.rb (renamed from lib/gitlab/markdown/combined_pipeline.rb)8
-rw-r--r--lib/banzai/pipeline/description_pipeline.rb (renamed from lib/gitlab/markdown/pipeline/description_pipeline.rb)8
-rw-r--r--lib/banzai/pipeline/email_pipeline.rb (renamed from lib/gitlab/markdown/pipeline/email_pipeline.rb)8
-rw-r--r--lib/banzai/pipeline/full_pipeline.rb (renamed from lib/gitlab/markdown/pipeline/full_pipeline.rb)6
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb41
-rw-r--r--lib/banzai/pipeline/note_pipeline.rb (renamed from lib/gitlab/markdown/pipeline/note_pipeline.rb)8
-rw-r--r--lib/banzai/pipeline/plain_markdown_pipeline.rb13
-rw-r--r--lib/banzai/pipeline/post_process_pipeline.rb20
-rw-r--r--lib/banzai/pipeline/reference_extraction_pipeline.rb13
-rw-r--r--lib/banzai/pipeline/single_line_pipeline.rb9
-rw-r--r--lib/banzai/reference_extractor.rb55
-rw-r--r--lib/banzai/renderer.rb78
-rw-r--r--lib/ci/api/helpers.rb2
-rw-r--r--lib/gitlab/asciidoc.rb2
-rw-r--r--lib/gitlab/backend/shell.rb2
-rw-r--r--lib/gitlab/bitbucket_import/project_creator.rb3
-rw-r--r--lib/gitlab/diff/file.rb4
-rw-r--r--lib/gitlab/fogbugz_import/importer.rb2
-rw-r--r--lib/gitlab/fogbugz_import/project_creator.rb3
-rw-r--r--lib/gitlab/git.rb4
-rw-r--r--lib/gitlab/gitlab_import/project_creator.rb3
-rw-r--r--lib/gitlab/gitorious_import/project_creator.rb3
-rw-r--r--lib/gitlab/google_code_import/importer.rb6
-rw-r--r--lib/gitlab/google_code_import/project_creator.rb3
-rw-r--r--lib/gitlab/markdown.rb115
-rw-r--r--lib/gitlab/markdown/cross_project_reference.rb24
-rw-r--r--lib/gitlab/markdown/pipeline.rb4
-rw-r--r--lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb13
-rw-r--r--lib/gitlab/markdown/pipeline/atom_pipeline.rb14
-rw-r--r--lib/gitlab/markdown/pipeline/gfm_pipeline.rb41
-rw-r--r--lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb13
-rw-r--r--lib/gitlab/markdown/pipeline/post_process_pipeline.rb20
-rw-r--r--lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb13
-rw-r--r--lib/gitlab/markdown/pipeline/single_line_pipeline.rb9
-rw-r--r--lib/gitlab/o_auth/session.rb17
-rw-r--r--lib/gitlab/reference_extractor.rb57
-rw-r--r--lib/rouge/formatters/html_gitlab.rb2
-rwxr-xr-xlib/support/init.d/gitlab13
-rwxr-xr-xlib/support/init.d/gitlab.default.example6
-rw-r--r--lib/support/nginx/gitlab146
-rw-r--r--lib/support/nginx/gitlab-ssl147
-rw-r--r--lib/tasks/gitlab/check.rake56
-rw-r--r--spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb2
-rw-r--r--spec/factories.rb3
-rw-r--r--spec/features/admin/admin_runners_spec.rb2
-rw-r--r--spec/features/ci_lint_spec.rb39
-rw-r--r--spec/features/commits_spec.rb29
-rw-r--r--spec/features/issues/filter_by_milestone_spec.rb4
-rw-r--r--spec/features/issues/note_polling_spec.rb16
-rw-r--r--spec/features/lint_spec.rb28
-rw-r--r--spec/features/merge_requests/merge_when_build_succeeds_spec.rb6
-rw-r--r--spec/features/projects_spec.rb14
-rw-r--r--spec/features/security/group_access_spec.rb4
-rw-r--r--spec/features/task_lists_spec.rb4
-rw-r--r--spec/helpers/application_helper_spec.rb7
-rw-r--r--spec/helpers/ci_status_helper_spec.rb11
-rw-r--r--spec/helpers/groups_helper.rb2
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb41
-rw-r--r--spec/helpers/projects_helper_spec.rb10
-rw-r--r--spec/javascripts/fixtures/issues_show.html.haml2
-rw-r--r--spec/javascripts/fixtures/merge_requests_show.html.haml2
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb (renamed from spec/lib/gitlab/markdown/cross_project_reference_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/autolink_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/commit_range_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/commit_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/emoji_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/emoji_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/external_issue_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/external_link_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/issue_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/label_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/merge_request_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/redactor_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/reference_gatherer_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/reference_gatherer_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/relative_link_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/sanitization_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/snippet_reference_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/syntax_highlight_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/table_of_contents_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/task_list_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/task_list_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/upload_link_filter_spec.rb)2
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb (renamed from spec/lib/gitlab/markdown/filter/user_reference_filter_spec.rb)2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb2
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb10
-rw-r--r--spec/models/build_spec.rb70
-rw-r--r--spec/models/ci/commit_spec.rb4
-rw-r--r--spec/models/concerns/mentionable_spec.rb13
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb23
-rw-r--r--spec/models/jira_issue_spec.rb30
-rw-r--r--spec/models/key_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb11
-rw-r--r--spec/models/note_spec.rb4
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb22
-rw-r--r--spec/models/project_services/jira_service_spec.rb118
-rw-r--r--spec/models/project_services/slack_service/note_message_spec.rb8
-rw-r--r--spec/models/project_spec.rb6
-rw-r--r--spec/models/user_spec.rb5
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb50
-rw-r--r--spec/requests/api/services_spec.rb2
-rw-r--r--spec/requests/ci/api/runners_spec.rb1
-rw-r--r--spec/services/create_commit_builds_service_spec.rb39
-rw-r--r--spec/services/git_push_service_spec.rb69
-rw-r--r--spec/services/git_tag_push_service_spec.rb16
-rw-r--r--spec/services/system_note_service_spec.rb61
-rw-r--r--spec/services/update_snippet_service_spec.rb2
-rw-r--r--spec/support/filter_spec_helper.rb36
-rw-r--r--spec/support/jira_service_helper.rb67
-rw-r--r--spec/support/repo_helpers.rb12
-rw-r--r--spec/workers/repository_fork_worker_spec.rb20
-rw-r--r--spec/workers/stuck_ci_builds_worker_spec.rb4
329 files changed, 17218 insertions, 1939 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index b4ca11c8343..89aa0591c31 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -76,7 +76,7 @@ Style/BlockEndNewline:
Description: 'Put end statement of multiline block on its own line.'
Enabled: true
-Style/Blocks:
+Style/BlockDelimiters:
Description: >-
Avoid using {...} for multi-line blocks (multiline chaining is
always ugly).
@@ -232,6 +232,10 @@ Style/EvenOdd:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'
Enabled: false
+Style/ExtraSpacing:
+ Description: 'Do not use unnecessary spacing.'
+ Enabled: false
+
Style/FileName:
Description: 'Use snake_case for source file names.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
@@ -431,6 +435,14 @@ Style/OpMethod:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg'
Enabled: false
+Style/ParallelAssignment:
+ Description: >-
+ Check for simple usages of parallel assignment.
+ It will only warn when the number of variables
+ matches on both sides of the assignment.
+ StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parallel-assignment'
+ Enabled: false
+
Style/ParenthesesAroundCondition:
Description: >-
Don't use parentheses around the condition of an
@@ -669,6 +681,13 @@ Style/TrailingWhitespace:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace'
Enabled: false
+Style/TrailingUnderscoreVariable:
+ Description: >-
+ Checks for the usage of unneeded trailing underscores at the
+ end of parallel variable assignment.
+ AllowNamedUnderscoreVariables: true
+ Enabled: false
+
Style/TrivialAccessors:
Description: 'Prefer attr_* methods to trivial readers/writers.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family'
@@ -690,11 +709,6 @@ Style/UnneededPercentQ:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q'
Enabled: false
-Style/UnneededPercentX:
- Description: 'Checks for %x when `` would do.'
- StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-x'
- Enabled: false
-
Style/VariableInterpolation:
Description: >-
Don't interpolate global, instance and class variables
@@ -778,6 +792,10 @@ Metrics/MethodLength:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods'
Enabled: false
+Metrics/ModuleLength:
+ Description: 'Avoid modules longer than 100 lines of code.'
+ Enabled: false
+
#################### Lint ################################
### Warnings
@@ -961,6 +979,12 @@ Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.'
Enabled: true
+Rails/Date:
+ Description: >-
+ Checks the correct usage of date aware methods,
+ such as Date.today, Date.current etc.
+ Enabled: false
+
Rails/DefaultScope:
Description: 'Checks if the argument passed to default_scope is a block.'
Enabled: false
@@ -987,6 +1011,12 @@ Rails/ScopeArgs:
Description: 'Checks the arguments of ActiveRecord scopes.'
Enabled: false
+Rails/TimeZone:
+ Description: 'Checks the correct usage of time zone aware methods.'
+ StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time'
+ Reference: 'http://danilenko.org/2012/7/6/rails_timezones'
+ Enabled: false
+
Rails/Validation:
Description: 'Use validates :attribute, hash of validations.'
Enabled: false
diff --git a/CHANGELOG b/CHANGELOG
index d4b0e3ccf00..41e09f8b992 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,11 +4,23 @@ v 8.4.0 (unreleased)
- Add "Frequently used" category to emoji picker
v 8.3.0 (unreleased)
+ - Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu)
+ - Implement new UI for group page
+ - Implement search inside emoji picker
+ - Add project permissions to all project API endpoints (Stan Hu)
+
+v 8.3.0
+ - Add CAS support (tduehr)
+ - Bump rack-attack to 4.3.1 for security fix (Stan Hu)
+ - API support for starred projects for authorized user (Zeger-Jan van de Weg)
+ - Add link to merge request on build detail page.
+ - Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
- - Merge when build succeeds (Zeger-Jan van de Weg)
- Provide better diagnostic message upon project creation errors (Stan Hu)
- Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
+ - Remove api credentials from link to build_page
+ - Deprecate GitLabCiService making it to always be inactive
- Bump gollum-lib to 4.1.0 (Stan Hu)
- Fix broken group avatar upload under "New group" (Stan Hu)
- Update project repositorize size and commit count during import:repos task (Stan Hu)
@@ -20,13 +32,16 @@ v 8.3.0 (unreleased)
- Fix 500 error when update group member permission
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
- Recognize issue/MR/snippet/commit links as references
+ - Backport JIRA features from EE to CE
- Add ignore whitespace change option to commit view
- Fire update hook from GitLab
+ - Allow account unlock via email
- Style warning about mentioning many people in a comment
- Fix: sort milestones by due date once again (Greg Smethells)
- Migrate all CI::Services and CI::WebHooks to Services and WebHooks
- Don't show project fork event as "imported"
- Add API endpoint to fetch merge request commits list
+ - Don't create CI status for refs that doesn't have .gitlab-ci.yml, even if the builds are enabled
- Expose events API with comment information and author info
- Fix: Ensure "Remove Source Branch" button is not shown when branch is being deleted. #3583
- Run custom Git hooks when branch is created or deleted.
@@ -58,6 +73,7 @@ v 8.3.0 (unreleased)
- Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
- Persist runners registration token in database
- Fix online editor should not remove newlines at the end of the file
+ - Expose Git's version in the admin area
v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu)
@@ -65,8 +81,6 @@ v 8.2.3
- Update documentation for "Guest" permissions
- Properly convert Emoji-only comments into Award Emojis
- Enable devise paranoid mode to prevent user enumeration attack
-
-v 8.2.3
- Webhook payload has an added, modified and removed properties for each commit
- Fix 500 error when creating a merge request that removes a submodule
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7ced7c57889..950824e35ab 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -358,7 +358,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[core team]: https://about.gitlab.com/core-team/
[getting help page]: https://about.gitlab.com/getting-help/
[Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
-[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up+for+grabs
+[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
[medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 743af5e1251..d48d3702aed 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.6.8
+2.6.9
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 2b7c5ae0184..4b9fcbec101 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.4.2
+0.5.1
diff --git a/Gemfile b/Gemfile
index 7298e21ce66..3d4345978a7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -23,6 +23,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
+gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
@@ -101,6 +102,9 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1'
+# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
+gem 'nokogiri', '1.6.7.1'
+
# Diffs
gem 'diffy', '~> 3.0.3'
@@ -175,7 +179,7 @@ gem "sanitize", '~> 2.0'
gem 'babosa', '~> 1.0.2'
# Protect against bruteforcing
-gem "rack-attack", '~> 4.3.0'
+gem "rack-attack", '~> 4.3.1'
# Ace editor
gem 'ace-rails-ap', '~> 2.0.1'
@@ -186,7 +190,7 @@ gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.3'
-gem "sass-rails", '~> 4.0.5'
+gem "sass-rails", '~> 5.0.0'
gem "coffee-rails", '~> 4.1.0'
gem "uglifier", '~> 2.7.2'
gem 'turbolinks', '~> 2.5.0'
@@ -198,9 +202,9 @@ gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.2.0'
gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2'
-gem 'jquery-rails', '~> 3.1.3'
+gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3'
-gem 'jquery-ui-rails', '~> 4.2.1'
+gem 'jquery-ui-rails', '~> 5.0.0'
gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
@@ -215,7 +219,7 @@ group :development do
gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2'
- gem 'rerun', '~> 0.10.0'
+ gem 'rerun', '~> 0.11.0'
gem 'bullet', require: false
gem 'rblineprof', platform: :mri, require: false
gem 'web-console', '~> 2.0'
@@ -251,7 +255,7 @@ group :development, :test do
gem 'capybara', '~> 2.4.0'
gem 'capybara-screenshot', '~> 1.0.0'
- gem 'poltergeist', '~> 1.6.0'
+ gem 'poltergeist', '~> 1.8.1'
gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine', '~> 2.2.0'
@@ -261,7 +265,7 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
- gem 'rubocop', '~> 0.28.0', require: false
+ gem 'rubocop', '~> 0.35.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index ff57460f5bb..7477b42f2d8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -117,23 +117,6 @@ GEM
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
json (>= 1.7)
- celluloid (0.17.2)
- celluloid-essentials
- celluloid-extras
- celluloid-fsm
- celluloid-pool
- celluloid-supervision
- timers (>= 4.1.1)
- celluloid-essentials (0.20.5)
- timers (>= 4.1.1)
- celluloid-extras (0.20.5)
- timers (>= 4.1.1)
- celluloid-fsm (0.20.5)
- timers (>= 4.1.1)
- celluloid-pool (0.20.5)
- timers (>= 4.1.1)
- celluloid-supervision (0.20.5)
- timers (>= 4.1.1)
charlock_holmes (0.7.3)
chunky_png (1.3.5)
cliver (0.3.2)
@@ -369,7 +352,6 @@ GEM
hipchat (1.5.2)
httparty
mimemagic
- hitimes (1.2.3)
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
@@ -390,15 +372,16 @@ GEM
inflecto (0.0.2)
ipaddress (0.8.0)
jquery-atwho-rails (1.3.2)
- jquery-rails (3.1.4)
- railties (>= 3.0, < 5.0)
+ jquery-rails (4.0.5)
+ rails-dom-testing (~> 1.0)
+ railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-scrollto-rails (1.4.3)
railties (> 3.1, < 5.0)
jquery-turbolinks (2.1.0)
railties (>= 3.1.0)
turbolinks
- jquery-ui-rails (4.2.1)
+ jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
json (1.8.3)
jwt (1.5.2)
@@ -410,8 +393,7 @@ GEM
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
- listen (2.9.0)
- celluloid (>= 0.15.2)
+ listen (3.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
loofah (2.0.3)
@@ -424,7 +406,7 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
- mini_portile (0.6.2)
+ mini_portile2 (2.0.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
multi_json (1.11.2)
@@ -439,8 +421,8 @@ GEM
grape
newrelic_rpm
newrelic_rpm (3.9.4.245)
- nokogiri (1.6.6.4)
- mini_portile (~> 0.6.0)
+ nokogiri (1.6.7.1)
+ mini_portile2 (~> 2.0.0.rc2)
nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
@@ -458,6 +440,10 @@ GEM
multi_json (~> 1.7)
omniauth (~> 1.1)
omniauth-oauth (~> 1.0)
+ omniauth-cas3 (1.1.3)
+ addressable (~> 2.3)
+ nokogiri (~> 1.6.6)
+ omniauth (~> 1.2)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
@@ -507,13 +493,13 @@ GEM
parser (2.2.3.0)
ast (>= 1.1, < 3.0)
pg (0.18.4)
- poltergeist (1.6.0)
+ poltergeist (1.8.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.11)
- powerpack (0.0.9)
+ powerpack (0.1.1)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
@@ -526,7 +512,7 @@ GEM
rack (1.6.4)
rack-accept (0.4.5)
rack (>= 0.4)
- rack-attack (4.3.0)
+ rack-attack (4.3.1)
rack
rack-cors (0.4.0)
rack-mount (0.8.3)
@@ -601,8 +587,8 @@ GEM
redis-store (1.1.7)
redis (>= 2.2)
request_store (1.2.1)
- rerun (0.10.0)
- listen (~> 2.7, >= 2.7.3)
+ rerun (0.11.0)
+ listen (~> 3.0)
responders (2.1.0)
railties (>= 4.2.0, < 5)
rest-client (1.8.0)
@@ -637,12 +623,13 @@ GEM
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)
- rubocop (0.28.0)
+ rubocop (0.35.1)
astrolabe (~> 1.3)
- parser (>= 2.2.0.pre.7, < 3.0)
- powerpack (~> 0.0.6)
+ parser (>= 2.2.3.0, < 3.0)
+ powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
- ruby-progressbar (~> 1.4)
+ ruby-progressbar (~> 1.7)
+ tins (<= 1.6.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
@@ -661,12 +648,13 @@ GEM
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
- sass (3.2.19)
- sass-rails (4.0.5)
+ sass (3.4.20)
+ sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
- sass (~> 3.2.2)
- sprockets (~> 2.8, < 3.0)
- sprockets-rails (~> 2.0)
+ sass (~> 3.1)
+ sprockets (>= 2.8, < 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+ tilt (>= 1.1, < 3)
sawyer (0.6.0)
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
@@ -758,8 +746,6 @@ GEM
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
- timers (4.1.1)
- hitimes
timfel-krb5-auth (0.8.3)
tinder (1.10.1)
eventmachine (~> 1.0)
@@ -894,10 +880,10 @@ DEPENDENCIES
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
jquery-atwho-rails (~> 1.3.2)
- jquery-rails (~> 3.1.3)
+ jquery-rails (~> 4.0.0)
jquery-scrollto-rails (~> 1.4.3)
jquery-turbolinks (~> 2.1.0)
- jquery-ui-rails (~> 4.2.1)
+ jquery-ui-rails (~> 5.0.0)
kaminari (~> 0.16.3)
letter_opener (~> 1.1.2)
mail_room (~> 0.6.1)
@@ -908,11 +894,13 @@ DEPENDENCIES
net-ssh (~> 3.0.1)
newrelic-grape
newrelic_rpm (~> 3.9.4.245)
+ nokogiri (= 1.6.7.1)
nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2)
+ omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
@@ -925,10 +913,10 @@ DEPENDENCIES
org-ruby (~> 0.9.12)
paranoia (~> 2.0)
pg (~> 0.18.2)
- poltergeist (~> 1.6.0)
+ poltergeist (~> 1.8.1)
pry-rails
quiet_assets (~> 1.0.2)
- rack-attack (~> 4.3.0)
+ rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rails (= 4.2.4)
@@ -940,15 +928,15 @@ DEPENDENCIES
redis-namespace
redis-rails (~> 4.0.0)
request_store (~> 1.2.0)
- rerun (~> 0.10.0)
+ rerun (~> 0.11.0)
responders (~> 2.0)
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0)
- rubocop (~> 0.28.0)
+ rubocop (~> 0.35.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
- sass-rails (~> 4.0.5)
+ sass-rails (~> 5.0.0)
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
diff --git a/VERSION b/VERSION
index 8d0676ff07b..ce669730119 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.3.0.pre
+8.4.0.pre
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 1539eba0faa..affab5bb030 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -5,7 +5,7 @@
# the compiled file.
#
#= require jquery
-#= require jquery.ui.all
+#= require jquery-ui
#= require jquery_ujs
#= require jquery.cookie
#= require jquery.endless-scroll
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index 0dc84b4c7ac..93860e3bbf3 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -11,6 +11,7 @@ class @AwardsHandler
$(".emoji-menu").hide()
@renderFrequentlyUsedBlock()
+ @setupSearch()
addAward: (emoji) ->
emoji = @normilizeEmojiName(emoji)
@@ -80,7 +81,7 @@ class @AwardsHandler
nodes = []
nodes.push("<div class='award active' title='me'>")
- nodes.push("<div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div>")
+ nodes.push("<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>")
nodes.push("<div class='counter'>1</div>")
nodes.push("</div>")
@@ -89,13 +90,19 @@ class @AwardsHandler
$(".award").tooltip()
resolveNameToCssClass: (emoji) ->
- unicodeName = $(".emoji-menu-content [data-emoji='?']".replace("?", emoji)).data("unicode-name")
+ emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']")
- "emoji-" + unicodeName
+ if emoji_icon.length > 0
+ unicodeName = emoji_icon.data("unicode-name")
+ else
+ # Find by alias
+ unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data("unicode-name")
+
+ "emoji-#{unicodeName}"
postEmoji: (emoji, callback) ->
$.post @post_emoji_url, { note: {
- note: ":" + emoji + ":"
+ note: ":#{emoji}:"
noteable_type: @noteable_type
noteable_id: @noteable_id
}},(data) ->
@@ -103,7 +110,7 @@ class @AwardsHandler
callback.call()
findEmojiIcon: (emoji) ->
- $(".award [data-emoji='" + emoji + "']")
+ $(".award [data-emoji='#{emoji}']")
scrollToAwards: ->
$('body, html').animate({
@@ -134,3 +141,22 @@ class @AwardsHandler
$(".emoji-menu-content").prepend(ul).prepend($("<h4>").text("Frequently used"))
+ setupSearch: ->
+ $("input.emoji-search").keyup (ev) =>
+ term = $(ev.target).val()
+
+ # Clean previous search results
+ $("ul.emoji-search,h5.emoji-search").remove()
+
+ if term
+ # Generate search result block
+ h5 = $("<h5>").text("Search results").addClass("emoji-search")
+ found_emojis = @searchEmojis(term).show()
+ ul = $("<ul>").addClass("emoji-search").append(found_emojis)
+ $(".emoji-menu-content ul, .emoji-menu-content h5").hide()
+ $(".emoji-menu-content").append(h5).append(ul)
+ else
+ $(".emoji-menu-content").children().show()
+
+ searchEmojis: (term)->
+ $(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone()
diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee
index 01bd515cc02..02232698bc2 100644
--- a/app/assets/javascripts/issuable_context.js.coffee
+++ b/app/assets/javascripts/issuable_context.js.coffee
@@ -18,7 +18,7 @@ class @IssuableContext
$('.issuable-affix').affix offset:
top: ->
- @top = ($('.issuable-affix').offset().top - 60)
+ @top = ($('.issuable-affix').offset().top - 70)
bottom: ->
@bottom = $('.footer').outerHeight(true)
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index 603a16da1ce..eff80bf63bb 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -10,12 +10,12 @@ class @Issue
@initTaskList()
initTaskList: ->
- $('.issue-details .js-task-list-container').taskList('enable')
- $(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList
+ $('.detail-page-description .js-task-list-container').taskList('enable')
+ $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
- $('.issue-details .js-task-list-container').taskList('disable')
- $(document).off 'tasklist:changed', '.issue-details .js-task-list-container'
+ $('.detail-page-description .js-task-list-container').taskList('disable')
+ $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the issue description inline-editable like a note so
# that we can re-use its form here
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index b21cb7904b5..9047587db81 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -40,12 +40,12 @@ class @MergeRequest
this.$('.all-commits').removeClass 'hide'
initTaskList: ->
- $('.merge-request-details .js-task-list-container').taskList('enable')
- $(document).on 'tasklist:changed', '.merge-request-details .js-task-list-container', @updateTaskList
+ $('.detail-page-description .js-task-list-container').taskList('enable')
+ $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
- $('.merge-request-details .js-task-list-container').taskList('disable')
- $(document).off 'tasklist:changed', '.merge-request-details .js-task-list-container'
+ $('.detail-page-description .js-task-list-container').taskList('disable')
+ $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the merge request description inline-editable like a
# note so that we can re-use its form here
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 7b060ce4853..0c0451fe4dd 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -2,8 +2,8 @@
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
- *= require jquery.ui.datepicker
- *= require jquery.ui.autocomplete
+ *= require jquery-ui/datepicker
+ *= require jquery-ui/autocomplete
*= require jquery.atwho
*= require select2
*= require_self
@@ -48,4 +48,4 @@
/*
* Styles for JS behaviors.
*/
-@import "behaviors.scss"; \ No newline at end of file
+@import "behaviors.scss";
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index a62c0f62a4c..206d39cc9b3 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -76,7 +76,7 @@
.cover-block {
text-align: center;
- background: #f7f8fa;
+ background: $background-color;
margin: -$gl-padding;
margin-bottom: 0;
padding: 44px $gl-padding;
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index fe56266284b..97a94638847 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -1,10 +1,9 @@
@mixin btn-default {
- @include border-radius(2px);
+ @include border-radius(3px);
border-width: 1px;
border-style: solid;
- text-transform: uppercase;
- font-size: 13px;
- font-weight: 600;
+ font-size: 15px;
+ font-weight: 500;
line-height: 18px;
padding: 11px $gl-padding;
letter-spacing: .4px;
@@ -18,7 +17,7 @@
@mixin btn-middle {
@include btn-default;
- @include border-radius(2px);
+ @include border-radius(3px);
padding: 11px 24px;
}
@@ -51,6 +50,10 @@
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
}
+@mixin btn-blue-medium {
+ @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF);
+}
+
@mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
}
@@ -60,7 +63,7 @@
}
@mixin btn-gray {
- @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, #313236);
+ @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236);
}
@mixin btn-white {
@@ -75,6 +78,10 @@
padding: 5px 10px;
}
+ &.btn-nr {
+ padding: 7px 10px;
+ }
+
&.btn-xs {
padding: 1px 5px;
}
@@ -91,11 +98,15 @@
@include btn-gray;
}
- &.btn-primary,
+ &.btn-primary {
+ @include btn-blue-medium;
+ }
+
&.btn-info {
@include btn-blue;
}
+ &.btn-close,
&.btn-warning {
@include btn-orange;
}
@@ -110,20 +121,8 @@
float: right;
}
- &.btn-close {
- color: $gl-danger;
- border-color: $gl-danger;
- &:hover {
- color: #B94A48;
- }
- }
-
&.btn-reopen {
- color: $gl-success;
- border-color: $gl-success;
- &:hover {
- color: #468847;
- }
+ /* should be same as parent class for now */
}
&.btn-grouped {
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 88da799ee2b..11730000f85 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -374,7 +374,7 @@ table {
}
}
-.center-top-menu {
+.center-top-menu, .left-top-menu {
@include nav-menu;
text-align: center;
margin-top: 5px;
@@ -401,6 +401,16 @@ table {
border-bottom: 1px solid $border-color;
height: 57px;
}
+
+ &.wide {
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ }
+}
+
+.left-top-menu {
+ text-align: left;
+ border-bottom: 1px solid #EEE;
}
.center-middle-menu {
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index f12d68b5a1f..e93dbab0c42 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -4,8 +4,8 @@
*
*/
-.issue-box {
- @include border-radius(2px);
+.status-box {
+ @include border-radius(3px);
display: block;
float: left;
@@ -14,22 +14,22 @@
margin-right: 10px;
font-size: $gl-font-size;
- &.issue-box-closed {
+ &.status-box-closed {
background-color: $gl-danger;
color: #FFF;
}
- &.issue-box-merged {
+ &.status-box-merged {
background-color: $gl-primary;
color: #FFF;
}
- &.issue-box-open {
- background-color: #019875;
+ &.status-box-open {
+ background-color: $green-light;
color: #FFF;
}
- &.issue-box-expired {
+ &.status-box-expired {
background: #cea61b;
color: #FFF;
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index aa5acb93cc5..a1a9990241d 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -5,7 +5,7 @@ html {
}
body {
- background-color: #EAEBEC !important;
+ background-color: #F3F3F3 !important;
&.navless {
background-color: white !important;
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index cc48f8c8166..1c74e525a60 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -143,7 +143,11 @@ ul.controls {
> li {
float: left;
- padding-right: 10px;
+ margin-right: 10px;
+
+ &:last-child {
+ margin-right: 0;
+ }
.author_link {
display: inline-block;
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 2b044786738..4a00a197d9a 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -87,7 +87,7 @@
.new_note,
.edit_note,
-.issuable-description,
+.detail-page-description,
.milestone-description,
.wiki-content,
.merge-request-form {
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 11c48d26ab5..41fd890f14f 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -123,7 +123,6 @@
padding: 0;
margin: 0;
list-style: none;
- margin-top: 5px;
height: 56px;
li {
@@ -131,9 +130,9 @@
a {
padding: 14px;
- font-size: 17px;
+ font-size: 15px;
line-height: 28px;
- color: #7f8fa4;
+ color: #959494;
border-bottom: 2px solid transparent;
&:hover, &:active, &:focus {
@@ -143,8 +142,8 @@
}
&.active a {
- color: #4c4e54;
- border-bottom: 2px solid #1cacfc;
+ color: #616060;
+ border-bottom: 2px solid #4688f1;
}
.badge {
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 6f44c323732..c00709fb6bb 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -81,7 +81,7 @@
display: none;
}
- .center-top-menu {
+ .center-top-menu, .left-top-menu {
li a {
font-size: 14px;
padding: 19px 10px;
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index 61053aff91a..57b9451b264 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -3,7 +3,6 @@
.panel-heading {
padding: 7px $gl-padding;
- line-height: 42px !important;
}
.panel-body {
@@ -15,3 +14,7 @@
}
}
}
+
+.container-blank .panel .panel-heading {
+ line-height: 42px !important;
+}
diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
index eb53c4153d3..ff41e26ed8a 100644
--- a/app/assets/stylesheets/framework/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -10,8 +10,7 @@
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
- border-bottom: 1px solid #ECEEF1;
- border-right: 1px solid #ECEEF1;
+ border-bottom: 1px solid $border-white-light;
&:target {
background: $hover;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 91954683c3e..af75123b0af 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -1,9 +1,9 @@
-$hover: #FFFAF1;
+$hover: #faf9f9;
$gl-text-color: #54565B;
$gl-text-green: #4A2;
$gl-text-red: #D12F19;
$gl-text-orange: #D90;
-$gl-header-color: #4c4e54;
+$gl-header-color: #323232;
$gl-link-color: #333c48;
$md-text-color: #444;
$md-link-color: #3084bb;
@@ -15,13 +15,14 @@ $sidebar_width: 230px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
-$border-color: #dce0e6;
+$border-color: #efeff1;
$table-border-color: #eef0f2;
-$background-color: #F7F8FA;
+$background-color: #faf9f9;
$header-height: 58px;
-$fixed-layout-width: 1200px;
-$gl-gray: #7f8fa4;
+$fixed-layout-width: 1280px;
+$gl-gray: #5a5a5a;
$gl-padding: 16px;
+$gl-padding-top:10px;
$gl-avatar-size: 46px;
/*
@@ -29,12 +30,12 @@ $gl-avatar-size: 46px;
*/
$white-light: #FFFFFF;
-$white-normal: #DCE0E5;
-$white-dark: #E4E7ED;
+$white-normal: #ededed;
+$white-dark: #ededed;
-$gray-light: #F0F2F5;
-$gray-normal: #DCE0E5;
-$gray-dark: #E4E7ED;
+$gray-light: #f7f7f7;
+$gray-normal: #ededed;
+$gray-dark: #ededed;
$green-light: #31AF64;
$green-normal: #2FAA60;
@@ -44,6 +45,10 @@ $blue-light: #2EA8E5;
$blue-normal: #2D9FD8;
$blue-dark: #2897CE;
+$blue-medium-light: #3498CB;
+$blue-medium: #2F8EBF;
+$blue-medium-dark: #2D86B4;
+
$orange-light: #FC6443;
$orange-normal: #E75E40;
$orange-dark: #CE5237;
@@ -52,11 +57,11 @@ $red-light: #F43263;
$red-normal: #E52C5A;
$red-dark: #D22852;
-$border-white-light: #E3E7EC;
+$border-white-light: #F1F2F4;
$border-white-normal: #D6DAE2;
$border-white-dark: #C6CACF;
-$border-gray-light: #DCE0E5;
+$border-gray-light: #d1d1d1;
$border-gray-normal: #D6DAE2;
$border-gray-dark: #C6CACF;
@@ -76,6 +81,8 @@ $border-red-light: #E52C5A;
$border-red-normal: #D22852;
$border-red-dark: #CA264F;
+/* header */
+$light-grey-header: #faf9f9;
/*
* State colors:
diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/pages/awards.scss
index 30fdf3f218d..19d0d361c79 100644
--- a/app/assets/stylesheets/pages/awards.scss
+++ b/app/assets/stylesheets/pages/awards.scss
@@ -90,13 +90,19 @@
height: 300px;
overflow-y: scroll;
- h4 {
+ h5 {
clear: left;
}
ul {
list-style-type: none;
margin-left: -20px;
+ margin-bottom: 20px;
+ overflow: auto;
+ }
+
+ input.emoji-search{
+ background: image-url(/assets/icon-search.png) 240px no-repeat;
}
li {
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
new file mode 100644
index 00000000000..deab805dbc2
--- /dev/null
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -0,0 +1,33 @@
+.detail-page-header {
+ margin: -$gl-padding;
+ padding: 7px $gl-padding;
+ margin-bottom: 0px;
+ border-bottom: 1px solid $border-color;
+ color: #5c5d5e;
+ font-size: 16px;
+ line-height: 34px;
+
+ .author {
+ color: #5c5d5e;
+ }
+
+ .identifier {
+ color: #5c5d5e;
+ }
+}
+
+.detail-page-description {
+ .title {
+ margin: 0;
+ font-size: 23px;
+ color: #313236;
+ }
+
+ .description {
+ margin-top: 6px;
+
+ p:last-child {
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/emojis.scss b/app/assets/stylesheets/pages/emojis.scss
index 819ec9a2f5f..920d0e3d338 100644
--- a/app/assets/stylesheets/pages/emojis.scss
+++ b/app/assets/stylesheets/pages/emojis.scss
@@ -4,7 +4,7 @@ The source: gemojione gem.
*/
.emoji-icon{
- background-image: url(emoji.png);
+ background-image: image-url(emoji.png);
background-repeat: no-repeat;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 797a0af3720..9da273a0b6b 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -18,7 +18,7 @@
&.affix {
position: fixed;
- top: 60px;
+ top: 70px;
margin-right: 35px;
}
}
@@ -36,33 +36,12 @@
}
.issuable-details {
- .issue-title {
- margin: 0;
- font-size: 23px;
- color: #313236;
- }
-
- .description {
- margin-top: 6px;
-
- p:last-child {
- margin-bottom: 0;
- }
- }
-
section {
- border-right: 1px solid #ECEEF1;
+ border-right: 1px solid $border-white-light;
- > .tab-content {
+ .issuable-discussion {
margin-right: 1px;
}
-
- .issue-discussion > .gray-content-block,
- > .gray-content-block {
- margin-top: 0;
- border-top: none;
- margin-right: -15px;
- }
}
}
@@ -136,21 +115,3 @@
margin-right: 2px;
}
}
-
-.issuable-title {
- margin: -$gl-padding;
- padding: 7px $gl-padding;
- margin-bottom: 0px;
- border-bottom: 1px solid $border-color;
- color: #5c5d5e;
- font-size: 16px;
- line-height: 42px;
-
- .author {
- color: #5c5d5e;
- }
-
- .issuable-id {
- color: #5c5d5e;
- }
-}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index a652b65502f..a02a3a72e79 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -141,11 +141,6 @@ form.edit-issue {
}
}
-.issue-closed-by-widget {
- padding: 16px 0;
- margin: 0px;
-}
-
.issue-form .select2-container {
width: 250px !important;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 502e9552acd..82effde0bf3 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -191,7 +191,7 @@
.btn-clipboard {
@extend .pull-right;
- margin-right: 18px;
+ margin-right: 20px;
margin-top: 5px;
position: absolute;
right: 0;
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index e1a72af0013..d86259f93fb 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -75,17 +75,15 @@
.common-note-form {
margin: 0;
- background: #F7F8FA;
+ background: #fff;
padding: $gl-padding;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
- border-right: 1px solid $border-color;
- border-top: 1px solid $border-color;
margin-bottom: -$gl-padding;
}
.note-form-actions {
- background: #F9F9F9;
+ background: #fff;
.note-form-option {
margin-top: 8px;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 4dff87abaa4..72b0ed29a69 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -128,7 +128,7 @@ ul.notes {
}
&:last-child {
- border-bottom: none;
+ border-bottom: 1px solid $border-color;
}
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 2ded32dba12..99006b9f5d1 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -335,6 +335,36 @@ ul.nav.nav-projects-tabs {
}
}
+.top-area {
+ border-bottom: 1px solid #EEE;
+
+ ul.left-top-menu {
+ display: inline-block;
+ width: 50%;
+ margin-bottom: 0px;
+ border-bottom: none;
+ }
+
+ .projects-search-form {
+ width: 50%;
+ display: inline-block;
+ float: right;
+ padding-top: 7px;
+ text-align: right;
+
+ .btn-green {
+ margin-top: -2px;
+ margin-left: 10px;
+ }
+ }
+
+ @media (max-width: $screen-xs-max) {
+ .projects-search-form {
+ padding-top: 15px;
+ }
+ }
+}
+
.fork-namespaces {
.fork-thumbnail {
text-align: center;
@@ -412,11 +442,18 @@ pre.light-well {
.projects-search-form {
margin: -$gl-padding;
- background-color: #f8fafc;
padding: $gl-padding;
margin-bottom: 0px;
- border-top: 1px solid #e7e9ed;
- border-bottom: 1px solid #e7e9ed;
+
+ input {
+ display: inline-block;
+ width: calc(100% - 151px);
+ }
+
+ .btn {
+ display: inline-block;
+ width: 135px;
+ }
}
.git-empty {
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index a7d3b2197f1..4b6ef035673 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -35,3 +35,20 @@
border-color: $gl-warning;
}
}
+
+.ci-status-icon-success {
+ @extend .cgreen;
+}
+.ci-status-icon-failed {
+ @extend .cred;
+}
+.ci-status-icon-running,
+.ci-status-icon-pending {
+ // These are standard text color
+}
+.ci-status-icon-canceled,
+.ci-status-icon-disabled,
+.ci-status-icon-not-found,
+.ci-status-icon-skipped {
+ @extend .cgray;
+}
diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb
index d28614731f9..e383fe38ea6 100644
--- a/app/controllers/admin/identities_controller.rb
+++ b/app/controllers/admin/identities_controller.rb
@@ -1,6 +1,21 @@
class Admin::IdentitiesController < Admin::ApplicationController
before_action :user
- before_action :identity, except: :index
+ before_action :identity, except: [:index, :new, :create]
+
+ def new
+ @identity = Identity.new
+ end
+
+ def create
+ @identity = Identity.new(identity_params)
+ @identity.user_id = user.id
+
+ if @identity.save
+ redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully created.'
+ else
+ render :new
+ end
+ end
def index
@identities = @user.identities
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 0d182e8eb04..01e2e7b2f98 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user_from_token!
before_action :authenticate_user!
+ before_action :validate_user_service_ticket!
before_action :reject_blocked!
before_action :check_password_expiration
before_action :ldap_security_check
@@ -202,6 +203,20 @@ class ApplicationController < ActionController::Base
end
end
+ def validate_user_service_ticket!
+ return unless signed_in? && session[:service_tickets]
+
+ valid = session[:service_tickets].all? do |provider, ticket|
+ Gitlab::OAuth::Session.valid?(provider, ticket)
+ end
+
+ unless valid
+ session[:service_tickets] = nil
+ sign_out current_user
+ redirect_to new_user_session_path
+ end
+ end
+
def check_password_expiration
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
redirect_to new_profile_password_path and return
diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb
index 7ed78ff8e98..e782a51e7eb 100644
--- a/app/controllers/ci/lints_controller.rb
+++ b/app/controllers/ci/lints_controller.rb
@@ -19,8 +19,10 @@ module Ci
@error = e.message
@status = false
rescue
- @error = "Undefined error"
+ @error = 'Undefined error'
@status = false
+ ensure
+ render :show
end
end
end
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index f4354c6d8ca..b3594d82530 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -1,6 +1,7 @@
class Dashboard::SnippetsController < Dashboard::ApplicationController
def index
- @snippets = SnippetsFinder.new.execute(current_user,
+ @snippets = SnippetsFinder.new.execute(
+ current_user,
filter: :by_user,
user: current_user,
scope: params[:scope]
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index f809fa7500a..4cad98b8e98 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -1,6 +1,6 @@
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
- protect_from_forgery except: [:kerberos, :saml]
+ protect_from_forgery except: [:kerberos, :saml, :cas3]
Gitlab.config.omniauth.providers.each do |provider|
define_method provider['name'] do
@@ -42,6 +42,14 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
render 'errors/omniauth_error', layout: "errors", status: 422
end
+ def cas3
+ ticket = params['ticket']
+ if ticket
+ handle_service_ticket oauth['provider'], ticket
+ end
+ handle_omniauth
+ end
+
private
def handle_omniauth
@@ -84,6 +92,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
redirect_to new_user_session_path
end
+ def handle_service_ticket provider, ticket
+ Gitlab::OAuth::Session.create provider, ticket
+ session[:service_tickets] ||= {}
+ session[:service_tickets][provider] = ticket
+ end
+
def oauth
@oauth ||= request.env['omniauth.auth']
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index fffd90d87eb..ab5c953189c 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -7,7 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds]
before_action :define_show_vars, only: [:show, :diffs, :commits, :builds]
- before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds]
+ before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds]
# Allow read any merge_request
@@ -153,11 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_check
- if @merge_request.unchecked?
- @merge_request.check_if_can_be_merged
- end
-
- closes_issues
+ @merge_request.check_if_can_be_merged if @merge_request.unchecked?
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end
@@ -178,7 +174,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil)
- if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active?
+ if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request)
@status = :merge_when_build_succeeds
@@ -299,6 +295,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def define_widget_vars
@ci_commit = @merge_request.ci_commit
+ closes_issues
end
def invalid_mr
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index d560b3df17d..6f1e186d408 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -13,7 +13,8 @@ class Projects::NotesController < Projects::ApplicationController
@notes.each do |note|
notes_json[:notes] << {
id: note.id,
- html: note_to_html(note)
+ html: note_to_html(note),
+ valid: note.valid?
}
end
@@ -68,7 +69,7 @@ class Projects::NotesController < Projects::ApplicationController
data = {
author: current_user,
is_award: true,
- note: note_params[:note].gsub(":", '')
+ note: note_params[:note].delete(":")
}
note = noteable.notes.find_by(data)
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index 6b52eccebf7..e49259c34b6 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -21,7 +21,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
if protected_branch &&
protected_branch.update_attributes(
- developers_can_push: params[:developers_can_push]
+ developers_can_push: params[:developers_can_push]
)
respond_to do |format|
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 6e7590260ff..8b2577aebe1 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -1,5 +1,5 @@
class Projects::ServicesController < Projects::ApplicationController
- ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain,
+ ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_url, :api_version, :subdomain,
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
:build_key, :server, :teamcity_url, :drone_url, :build_type,
@@ -10,7 +10,8 @@ class Projects::ServicesController < Projects::ApplicationController
:notify_only_broken_builds, :add_pusher,
:send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color,
- :server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
+ :server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
+ :jira_issue_transition_id]
# Parameters to ignore if no value is specified
FILTER_BLANK_PARAMS = [:password]
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 21f962df206..0b00b9a0702 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -61,7 +61,7 @@ module ApplicationHelper
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
- style = "background-color: ##{ allowed_colors.values[bg_key] }; color: #555"
+ style = "background-color: ##{allowed_colors.values[bg_key]}; color: #555"
content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase
@@ -204,12 +204,16 @@ module ApplicationHelper
# Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
element = content_tag :time, time.to_s,
- class: "#{html_class} js-timeago",
+ class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601,
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
data: { toggle: 'tooltip', placement: placement, container: 'body' }
- element += javascript_tag "$('.js-timeago').last().timeago()" unless skip_js
+ unless skip_js
+ element << javascript_tag(
+ "$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
+ )
+ end
element
end
diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 313b6dde910..ec0e3f409c1 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -10,8 +10,8 @@ module ButtonHelper
# # => "<button class='...' data-clipboard-text='Foo'>...</button>"
#
# # Define the target element
- # clipboard_button(clipboard_target: "#foo")
- # # => "<button class='...' data-clipboard-target='#foo'>...</button>"
+ # clipboard_button(clipboard_target: "div#foo")
+ # # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
#
# See http://clipboardjs.com/#usage
def clipboard_button(data = {})
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 8554074d619..d8bee21c82e 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -12,19 +12,6 @@ module CiStatusHelper
ci_label_for_status(ci_commit.status)
end
- def ci_status_color(ci_commit)
- case ci_commit.status
- when 'success'
- 'green'
- when 'failed'
- 'red'
- when 'running', 'pending'
- 'yellow'
- else
- 'gray'
- end
- end
-
def ci_status_with_icon(status)
content_tag :span, class: "ci-status ci-#{status}" do
ci_icon_for_status(status) + '&nbsp;'.html_safe + ci_label_for_status(status)
@@ -56,12 +43,11 @@ module CiStatusHelper
end
def render_ci_status(ci_commit)
- link_to ci_status_path(ci_commit),
- class: "ci-status-link c#{ci_status_color(ci_commit)}",
+ link_to ci_status_icon(ci_commit),
+ ci_status_path(ci_commit),
+ class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
title: "Build #{ci_status_label(ci_commit)}",
- data: { toggle: 'tooltip', placement: 'left' } do
- ci_status_icon(ci_commit)
- end
+ data: { toggle: 'tooltip', placement: 'left' }
end
def no_runners_for_project?(project)
diff --git a/app/helpers/external_wiki_helper.rb b/app/helpers/external_wiki_helper.rb
index 838b85afdfe..1f3401f2906 100644
--- a/app/helpers/external_wiki_helper.rb
+++ b/app/helpers/external_wiki_helper.rb
@@ -1,7 +1,7 @@
module ExternalWikiHelper
def get_project_wiki_path(project)
external_wiki_service = project.services.
- select { |service| service.to_param == 'external_wiki' }.first
+ find { |service| service.to_param == 'external_wiki' }
if external_wiki_service.present? && external_wiki_service.active?
external_wiki_service.properties['external_wiki_url']
else
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 5004e02ea0b..ca41657cec1 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -20,7 +20,7 @@ module GitlabMarkdownHelper
end
user = current_user if defined?(current_user)
- gfm_body = Gitlab::Markdown.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
+ gfm_body = Banzai.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
@@ -50,7 +50,7 @@ module GitlabMarkdownHelper
context[:project] ||= @project
- html = Gitlab::Markdown.render(text, context)
+ html = Banzai.render(text, context)
context.merge!(
current_user: (current_user if defined?(current_user)),
@@ -61,11 +61,12 @@ module GitlabMarkdownHelper
ref: @ref
)
- Gitlab::Markdown.post_process(html, context)
+ Banzai.post_process(html, context)
end
def asciidoc(text)
- Gitlab::Asciidoc.render(text,
+ Gitlab::Asciidoc.render(
+ text,
project: @project,
current_user: (current_user if defined?(current_user)),
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index bd568d64e4b..4fe84322199 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -57,15 +57,15 @@ module IssuesHelper
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
end
- def issue_box_class(item)
+ def status_box_class(item)
if item.respond_to?(:expired?) && item.expired?
- 'issue-box-expired'
+ 'status-box-expired'
elsif item.respond_to?(:merged?) && item.merged?
- 'issue-box-merged'
+ 'status-box-merged'
elsif item.closed?
- 'issue-box-closed'
+ 'status-box-closed'
else
- 'issue-box-open'
+ 'status-box-open'
end
end
@@ -94,12 +94,13 @@ module IssuesHelper
end.sort.to_sentence(last_word_connector: ', or ')
end
- def emoji_icon(name, unicode = nil)
+ def emoji_icon(name, unicode = nil, aliases = [])
unicode ||= Emoji.emoji_filename(name)
content_tag :div, "",
class: "icon emoji-icon emoji-#{unicode}",
"data-emoji" => name,
+ "data-aliases" => aliases.join(" "),
"data-unicode-name" => unicode
end
@@ -119,6 +120,6 @@ module IssuesHelper
end
end
- # Required for Gitlab::Markdown::IssueReferenceFilter
+ # Required for Banzai::Filter::IssueReferenceFilter
module_function :url_for_issue
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 795fb439f25..a2c3d4d2f32 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -107,6 +107,6 @@ module LabelsHelper
options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
end
- # Required for Gitlab::Markdown::LabelReferenceFilter
+ # Required for Banzai::Filter::LabelReferenceFilter
module_function :render_colored_label, :text_color_for_bg, :escape_once
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 6c32647594d..1dd07a2a220 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -27,7 +27,16 @@ module MergeRequestsHelper
end
def ci_build_details_path(merge_request)
- merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
+ build_url = merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
+ return nil unless build_url
+
+ parsed_url = URI.parse(build_url)
+
+ unless parsed_url.userinfo.blank?
+ parsed_url.userinfo = ''
+ end
+
+ parsed_url.to_s
end
def merge_path_description(merge_request, separator)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index d061136b7b8..77ba612548a 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -105,6 +105,14 @@ module ProjectsHelper
end
end
+ def user_max_access_in_project(user_id, project)
+ level = project.team.max_member_access(user_id)
+
+ if level
+ Gitlab::Access.options_with_owner.key(level)
+ end
+ end
+
private
def get_project_nav_tabs(project, current_user)
@@ -277,14 +285,6 @@ module ProjectsHelper
end
end
- def user_max_access_in_project(user, project)
- level = project.team.max_member_access(user)
-
- if level
- Gitlab::Access.options_with_owner.key(level)
- end
- end
-
def leave_project_message(project)
"Are you sure you want to leave \"#{project.name}\" project?"
end
@@ -330,10 +330,9 @@ module ProjectsHelper
def filename_path(project, filename)
if project && blob = project.repository.send(filename)
namespace_project_blob_path(
- project.namespace,
- project,
- tree_join(project.default_branch,
- blob.name)
+ project.namespace,
+ project,
+ tree_join(project.default_branch, blob.name)
)
end
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 886a1e734b5..f448dd0ab61 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -79,7 +79,7 @@ module TreeHelper
part_path = File.join(part_path, part) unless part_path.empty?
part_path = part if part_path.empty?
- next unless parts.last(2).include?(part) if parts.count > max_links
+ next if parts.count > max_links && !parts.last(2).include?(part)
yield(part, tree_join(@ref, part_path))
end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 9beb0de68f3..3bbdd9cee76 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -17,7 +17,7 @@ class Notify < BaseMailer
subject: subject,
body: body.html_safe,
content_type: 'text/html'
- )
+ )
end
# Splits "gitlab.corp.company.com" up into "gitlab.corp.company.com",
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index faa0bdf840b..724429e7558 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -126,12 +126,16 @@ class ApplicationSetting < ActiveRecord::Base
def restricted_signup_domains_raw=(values)
self.restricted_signup_domains = []
self.restricted_signup_domains = values.split(
- /\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
- | # or
- \s # any whitespace character
- | # or
- [\r\n] # any number of newline characters
- /x)
+ /\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
+ | # or
+ \s # any whitespace character
+ | # or
+ [\r\n] # any number of newline characters
+ /x)
self.restricted_signup_domains.reject! { |d| d.empty? }
end
+
+ def runners_registration_token
+ ensure_runners_registration_token!
+ end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 6d9cdb95295..7b89fe069ea 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -135,6 +135,16 @@ module Ci
predefined_variables + yaml_variables + project_variables + trigger_variables
end
+ def merge_request
+ merge_requests = MergeRequest.includes(:merge_request_diff)
+ .where(source_branch: ref, source_project_id: commit.gl_project_id)
+ .reorder(iid: :asc)
+
+ merge_requests.find do |merge_request|
+ merge_request.commits.any? { |ci| ci.id == commit.sha }
+ end
+ end
+
def project
commit.project
end
@@ -170,7 +180,8 @@ module Ci
def extract_coverage(text, regex)
begin
- matches = text.gsub(Regexp.new(regex)).to_a.last
+ matches = text.scan(Regexp.new(regex)).last
+ matches = matches.last if matches.kind_of?(Array)
coverage = matches.gsub(/\d+(\.\d+)?/).first
if coverage.present?
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index 6bf596e5d3e..d2a29236942 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -218,16 +218,6 @@ module Ci
update!(committed_at: DateTime.now)
end
- ##
- # This method checks if build status should be displayed.
- #
- # Build status should be available only if builds are enabled
- # on project level and `.gitlab-ci.yml` file is present.
- #
- def show_build_status?
- project.builds_enabled? && ci_yaml_file
- end
-
private
def save_yaml_error(error)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index d2ea9ab7313..1fdcda97520 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -23,7 +23,7 @@ module Mentionable
included do
if self < Participable
- participant ->(current_user) { mentioned_users(current_user, load_lazy_references: false) }
+ participant ->(current_user) { mentioned_users(current_user) }
end
end
@@ -43,15 +43,15 @@ module Mentionable
self
end
- def all_references(current_user = self.author, text = nil, load_lazy_references: true)
- ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
-
+ def all_references(current_user = self.author, text = nil)
+ ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
+
if text
ext.analyze(text)
else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
- options[:cache_key] = [self, attr] if options.delete(:cache)
+ options[:cache_key] = [self, attr] if options.delete(:cache) && self.persisted?
ext.analyze(text, options)
end
end
@@ -59,13 +59,13 @@ module Mentionable
ext
end
- def mentioned_users(current_user = nil, load_lazy_references: true)
- all_references(current_user, load_lazy_references: load_lazy_references).users
+ def mentioned_users(current_user = nil)
+ all_references(current_user).users
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
- def referenced_mentionables(current_user = self.author, text = nil, load_lazy_references: true)
- refs = all_references(current_user, text, load_lazy_references: load_lazy_references)
+ def referenced_mentionables(current_user = self.author, text = nil)
+ refs = all_references(current_user, text)
refs = (refs.issues + refs.merge_requests + refs.commits)
# We're using this method instead of Array diffing because that requires
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 85367f89f4f..fc6f83b918b 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -37,21 +37,22 @@ module Participable
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
- def participants(current_user = self.author, load_lazy_references: true)
- participants = self.class.participant_attrs.flat_map do |attr|
- value =
- if attr.respond_to?(:call)
- instance_exec(current_user, &attr)
- else
- send(attr)
- end
+ def participants(current_user = self.author)
+ participants =
+ Gitlab::ReferenceExtractor.lazily do
+ self.class.participant_attrs.flat_map do |attr|
+ value =
+ if attr.respond_to?(:call)
+ instance_exec(current_user, &attr)
+ else
+ send(attr)
+ end
- participants_for(value, current_user)
- end.compact.uniq
-
- if load_lazy_references
- participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
+ participants_for(value, current_user)
+ end.compact.uniq
+ end
+ unless Gitlab::ReferenceExtractor.lazy?
participants.select! do |user|
user.can?(:read_project, project)
end
@@ -64,12 +65,12 @@ module Participable
def participants_for(value, current_user = nil)
case value
- when User, Gitlab::Markdown::ReferenceFilter::LazyReference
+ when User, Banzai::LazyReference
[value]
when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) }
when Participable
- value.participants(current_user, load_lazy_references: false)
+ value.participants(current_user)
end
end
end
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
index 56d38fe8250..885deaf78d2 100644
--- a/app/models/concerns/token_authenticatable.rb
+++ b/app/models/concerns/token_authenticatable.rb
@@ -13,20 +13,21 @@ module TokenAuthenticatable
@token_fields << token_field
define_singleton_method("find_by_#{token_field}") do |token|
- where(token_field => token).first if token
+ find_by(token_field => token) if token
end
define_method("ensure_#{token_field}") do
current_token = read_attribute(token_field)
- if current_token.blank?
- write_attribute(token_field, generate_token_for(token_field))
- else
- current_token
- end
+ current_token.blank? ? write_new_token(token_field) : current_token
+ end
+
+ define_method("ensure_#{token_field}!") do
+ send("reset_#{token_field}!") if read_attribute(token_field).blank?
+ read_attribute(token_field)
end
define_method("reset_#{token_field}!") do
- write_attribute(token_field, generate_token_for(token_field))
+ write_new_token(token_field)
save!
end
end
@@ -34,10 +35,15 @@ module TokenAuthenticatable
private
- def generate_token_for(token_field)
+ def write_new_token(token_field)
+ new_token = generate_token(token_field)
+ write_attribute(token_field, new_token)
+ end
+
+ def generate_token(token_field)
loop do
token = Devise.friendly_token
- break token unless self.class.unscoped.where(token_field => token).first
+ break token unless self.class.unscoped.find_by(token_field => token)
end
end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index e04035b3af8..80ecd15077f 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -84,11 +84,11 @@ class Issue < ActiveRecord::Base
end
def referenced_merge_requests
- references = [self, *notes].flat_map do |note|
- note.all_references(load_lazy_references: false).merge_requests
- end.uniq
-
- Gitlab::Markdown::ReferenceFilter::LazyReference.load(references).uniq.sort_by(&:iid)
+ Gitlab::ReferenceExtractor.lazily do
+ [self, *notes].flat_map do |note|
+ note.all_references.merge_requests
+ end
+ end.sort_by(&:iid)
end
# Reset issue events cache
diff --git a/app/models/jira_issue.rb b/app/models/jira_issue.rb
new file mode 100644
index 00000000000..5b21aac5e43
--- /dev/null
+++ b/app/models/jira_issue.rb
@@ -0,0 +1,2 @@
+class JiraIssue < ExternalIssue
+end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index f6f77a16267..ac25d38eb63 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -194,9 +194,7 @@ class MergeRequest < ActiveRecord::Base
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any?
errors.add :validate_branches,
- "Cannot Create: This merge request already exists: #{
- similar_mrs.pluck(:title)
- }"
+ "Cannot Create: This merge request already exists: #{similar_mrs.pluck(:title)}"
end
end
end
@@ -337,7 +335,7 @@ class MergeRequest < ActiveRecord::Base
issues = commits.flat_map { |c| c.closes_issues(current_user) }
issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
closed_by_message(description))
- issues.uniq
+ issues.uniq(&:id)
else
[]
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 1c4e101cc10..adafabbec07 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -45,7 +45,7 @@ class Namespace < ActiveRecord::Base
class << self
def by_path(path)
- where('lower(path) = :value', value: path.downcase).first
+ find_by('lower(path) = :value', value: path.downcase)
end
# Case insensetive search for namespace by path or name
@@ -148,6 +148,6 @@ class Namespace < ActiveRecord::Base
end
def find_fork_of(project)
- projects.joins(:forked_project_link).where('forked_project_links.forked_from_project_id = ?', project.id).first
+ projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 04053ccc61e..8c5b5836f9a 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -373,11 +373,11 @@ class Note < ActiveRecord::Base
end
def contains_emoji_only?
- note =~ /\A#{Gitlab::Markdown::EmojiFilter.emoji_pattern}\s?\Z/
+ note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/
end
def award_emoji_name
- original_name = note.match(Gitlab::Markdown::EmojiFilter.emoji_pattern)[1]
+ original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
AwardEmoji.normilize_emoji_name(original_name)
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index e1f7bf971e3..b28a7ca429c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -265,7 +265,7 @@ class Project < ActiveRecord::Base
joins(:namespace).
iwhere('namespaces.path' => namespace_path)
- projects.where('projects.path' => project_path).take ||
+ projects.find_by('projects.path' => project_path) ||
projects.iwhere('projects.path' => project_path).take
end
@@ -450,7 +450,7 @@ class Project < ActiveRecord::Base
end
def external_issue_tracker
- @external_issues_tracker ||= external_issues_trackers.select(&:activated?).first
+ @external_issues_tracker ||= external_issues_trackers.find(&:activated?)
end
def can_have_issues_tracker_id?
@@ -496,7 +496,11 @@ class Project < ActiveRecord::Base
end
def ci_service
- @ci_service ||= ci_services.select(&:activated?).first
+ @ci_service ||= ci_services.find(&:activated?)
+ end
+
+ def jira_tracker?
+ issues_tracker.to_param == 'jira'
end
def avatar_type
@@ -547,7 +551,7 @@ class Project < ActiveRecord::Base
end
def project_member_by_name_or_email(name = nil, email = nil)
- user = users.where('name like ? or email like ?', name, email).first
+ user = users.find_by('name like ? or email like ?', name, email)
project_members.where(user: user) if user
end
@@ -722,7 +726,7 @@ class Project < ActiveRecord::Base
end
def project_member(user)
- project_members.where(user_id: user).first
+ project_members.find_by(user_id: user)
end
def default_branch
@@ -799,6 +803,10 @@ class Project < ActiveRecord::Base
false
end
+ def jira_tracker_active?
+ jira_tracker? && jira_service.active
+ end
+
def ci_commit(sha)
ci_commits.find_by(sha: sha)
end
@@ -850,4 +858,8 @@ class Project < ActiveRecord::Base
def build_timeout_in_minutes=(value)
self.build_timeout = value.to_i * 60
end
+
+ def open_issues_count
+ issues.opened.count
+ end
end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 0a61ad96a0e..aa8746beb80 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -27,12 +27,10 @@ class BambooService < CiService
validates :build_key, presence: true, if: :activated?
validates :username,
presence: true,
- if: ->(service) { service.password? },
- if: :activated?
+ if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
- if: ->(service) { service.username? },
- if: :activated?
+ if: ->(service) { service.activated? && service.username }
attr_accessor :response
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 27fc19379f1..15c7c907f7e 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -58,6 +58,6 @@ class FlowdockService < Service
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
- )
+ )
end
end
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 91ef267ad79..202fee042e3 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -57,6 +57,6 @@ class GemnasiumService < Service
token: token,
api_key: api_key,
repo: project.repository.path_to_repo
- )
+ )
end
end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index d73182d40ac..b64d97ce75d 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -18,6 +18,11 @@
# note_events :boolean default(TRUE), not null
#
+# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
class GitlabCiService < CiService
- # this is no longer used
+ # We override the active accessor to always make GitLabCiService disabled
+ # Otherwise the GitLabCiService can be picked, but should never be since it's deprecated
+ def active
+ false
+ end
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 35e30b1cb0b..e216f406e1c 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -19,9 +19,24 @@
#
class JiraService < IssueTrackerService
+ include HTTParty
include Gitlab::Application.routes.url_helpers
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ DEFAULT_API_VERSION = 2
+
+ prop_accessor :username, :password, :api_url, :jira_issue_transition_id,
+ :title, :description, :project_url, :issues_url, :new_issue_url
+
+ before_validation :set_api_url, :set_jira_issue_transition_id
+
+ before_update :reset_password
+
+ def reset_password
+ # don't reset the password if a new one is provided
+ if api_url_changed? && !password_touched?
+ self.password = nil
+ end
+ end
def help
line1 = 'Setting `project_url`, `issues_url` and `new_issue_url` will '\
@@ -54,4 +69,228 @@ class JiraService < IssueTrackerService
def to_param
'jira'
end
+
+ def fields
+ super.push(
+ { type: 'text', name: 'api_url', placeholder: 'https://jira.example.com/rest/api/2' },
+ { type: 'text', name: 'username', placeholder: '' },
+ { type: 'password', name: 'password', placeholder: '' },
+ { type: 'text', name: 'jira_issue_transition_id', placeholder: '2' }
+ )
+ end
+
+ def execute(push, issue = nil)
+ if issue.nil?
+ # No specific issue, that means
+ # we just want to test settings
+ test_settings
+ else
+ close_issue(push, issue)
+ end
+ end
+
+ def create_cross_reference_note(mentioned, noteable, author)
+ issue_name = mentioned.id
+ project = self.project
+ noteable_name = noteable.class.name.underscore.downcase
+ noteable_id = if noteable.is_a?(Commit)
+ noteable.id
+ else
+ noteable.iid
+ end
+
+ entity_url = build_entity_url(noteable_name.to_sym, noteable_id)
+
+ data = {
+ user: {
+ name: author.name,
+ url: resource_url(user_path(author)),
+ },
+ project: {
+ name: project.path_with_namespace,
+ url: resource_url(namespace_project_path(project.namespace, project))
+ },
+ entity: {
+ name: noteable_name.humanize.downcase,
+ url: entity_url
+ }
+ }
+
+ add_comment(data, issue_name)
+ end
+
+ def test_settings
+ result = JiraService.get(
+ jira_api_test_url,
+ headers: {
+ 'Content-Type' => 'application/json',
+ 'Authorization' => "Basic #{auth}"
+ }
+ )
+
+ case result.code
+ when 201, 200
+ Rails.logger.info("#{self.class.name} SUCCESS #{result.code}: Successfully connected to #{api_url}.")
+ true
+ else
+ Rails.logger.info("#{self.class.name} ERROR #{result.code}: #{result.parsed_response}")
+ false
+ end
+ rescue Errno::ECONNREFUSED => e
+ Rails.logger.info "#{self.class.name} ERROR: #{e.message}. API URL: #{api_url}."
+ false
+ end
+
+ private
+
+ def build_api_url_from_project_url
+ server = URI(project_url)
+ default_ports = [["http",80],["https",443]].include?([server.scheme,server.port])
+ server_url = "#{server.scheme}://#{server.host}"
+ server_url.concat(":#{server.port}") unless default_ports
+ "#{server_url}/rest/api/#{DEFAULT_API_VERSION}"
+ rescue
+ "" # looks like project URL was not valid
+ end
+
+ def set_api_url
+ self.api_url = build_api_url_from_project_url if self.api_url.blank?
+ end
+
+ def set_jira_issue_transition_id
+ self.jira_issue_transition_id ||= "2"
+ end
+
+ def close_issue(entity, issue)
+ commit_id = if entity.is_a?(Commit)
+ entity.id
+ elsif entity.is_a?(MergeRequest)
+ entity.last_commit.id
+ end
+ commit_url = build_entity_url(:commit, commit_id)
+
+ # Depending on the JIRA project's workflow, a comment during transition
+ # may or may not be allowed. Split the operation in to two calls so the
+ # comment always works.
+ transition_issue(issue)
+ add_issue_solved_comment(issue, commit_id, commit_url)
+ end
+
+ def transition_issue(issue)
+ message = {
+ transition: {
+ id: jira_issue_transition_id
+ }
+ }
+ send_message(close_issue_url(issue.iid), message.to_json)
+ end
+
+ def add_issue_solved_comment(issue, commit_id, commit_url)
+ comment = {
+ body: "Issue solved with [#{commit_id}|#{commit_url}]."
+ }
+
+ send_message(comment_url(issue.iid), comment.to_json)
+ end
+
+ def add_comment(data, issue_name)
+ url = comment_url(issue_name)
+ user_name = data[:user][:name]
+ user_url = data[:user][:url]
+ entity_name = data[:entity][:name]
+ entity_url = data[:entity][:url]
+ project_name = data[:project][:name]
+
+ message = {
+ body: "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]."
+ }
+
+ unless existing_comment?(issue_name, message[:body])
+ send_message(url, message.to_json)
+ end
+ end
+
+
+ def auth
+ require 'base64'
+ Base64.urlsafe_encode64("#{self.username}:#{self.password}")
+ end
+
+ def send_message(url, message)
+ result = JiraService.post(
+ url,
+ body: message,
+ headers: {
+ 'Content-Type' => 'application/json',
+ 'Authorization' => "Basic #{auth}"
+ }
+ )
+
+ message = case result.code
+ when 201, 200, 204
+ "#{self.class.name} SUCCESS #{result.code}: Successfully posted to #{url}."
+ when 401
+ "#{self.class.name} ERROR 401: Unauthorized. Check the #{self.username} credentials and JIRA access permissions and try again."
+ else
+ "#{self.class.name} ERROR #{result.code}: #{result.parsed_response}"
+ end
+
+ Rails.logger.info(message)
+ message
+ rescue URI::InvalidURIError, Errno::ECONNREFUSED => e
+ Rails.logger.info "#{self.class.name} ERROR: #{e.message}. Hostname: #{url}."
+ end
+
+ def existing_comment?(issue_name, new_comment)
+ result = JiraService.get(
+ comment_url(issue_name),
+ headers: {
+ 'Content-Type' => 'application/json',
+ 'Authorization' => "Basic #{auth}"
+ }
+ )
+
+ case result.code
+ when 201, 200
+ existing_comments = JSON.parse(result.body)['comments']
+
+ if existing_comments.present?
+ return existing_comments.map { |comment| comment['body'].include?(new_comment) }.any?
+ end
+ end
+
+ false
+ rescue JSON::ParserError
+ false
+ end
+
+ def resource_url(resource)
+ "#{Settings.gitlab['url'].chomp("/")}#{resource}"
+ end
+
+ def build_entity_url(entity_name, entity_id)
+ resource_url(
+ polymorphic_url(
+ [
+ self.project.namespace.becomes(Namespace),
+ self.project,
+ entity_name
+ ],
+ id: entity_id,
+ routing_type: :path
+ )
+ )
+ end
+
+ def close_issue_url(issue_name)
+ "#{self.api_url}/issue/#{issue_name}/transitions"
+ end
+
+ def comment_url(issue_name)
+ "#{self.api_url}/issue/#{issue_name}/comment"
+ end
+
+ def jira_api_test_url
+ "#{self.api_url}/myself"
+ end
end
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 29d4236745a..a63700693d7 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -27,12 +27,10 @@ class TeamcityService < CiService
validates :build_type, presence: true, if: :activated?
validates :username,
presence: true,
- if: ->(service) { service.password? },
- if: :activated?
+ if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
- if: ->(service) { service.username? },
- if: :activated?
+ if: ->(service) { service.activated? && service.username }
attr_accessor :response
@@ -147,6 +145,6 @@ class TeamcityService < CiService
'</build>',
headers: { 'Content-type' => 'application/xml' },
basic_auth: auth
- )
+ )
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index fdd14f4571d..df87f3b79bd 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -26,6 +26,7 @@
# bio :string(255)
# failed_attempts :integer default(0)
# locked_at :datetime
+# unlock_token :string(255)
# username :string(255)
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
@@ -220,9 +221,9 @@ class User < ActiveRecord::Base
def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
- where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first
+ where(conditions).find_by("lower(username) = :value OR lower(email) = :value", value: login.downcase)
else
- where(conditions).first
+ find_by(conditions)
end
end
@@ -285,7 +286,7 @@ class User < ActiveRecord::Base
end
def by_username_or_id(name_or_id)
- where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
+ find_by('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i)
end
def build_user(attrs = {})
diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb
index 759c334ebe9..31b407efeb1 100644
--- a/app/services/create_commit_builds_service.rb
+++ b/app/services/create_commit_builds_service.rb
@@ -16,9 +16,23 @@ class CreateCommitBuildsService
return false
end
- tag = Gitlab::Git.tag_ref?(origin_ref)
- commit = project.ensure_ci_commit(sha)
+ commit = project.ci_commit(sha)
+ unless commit
+ commit = project.ci_commits.new(sha: sha)
+
+ # Skip creating ci_commit when no gitlab-ci.yml is found
+ unless commit.ci_yaml_file
+ return false
+ end
+
+ # Create a new ci_commit
+ commit.save!
+ end
+
+ # Skip creating builds for commits that have [ci skip]
unless commit.skip_ci?
+ # Create builds for commit
+ tag = Gitlab::Git.tag_ref?(origin_ref)
commit.update_committed!
commit.create_builds(ref, tag, user)
end
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 3d85f97b7e5..a1a20e47681 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -1,6 +1,11 @@
module Issues
class CloseService < Issues::BaseService
def execute(issue, commit = nil)
+ if project.jira_tracker? && project.jira_service.active
+ project.jira_service.execute(commit, issue)
+ return issue
+ end
+
if project.default_issues_tracker? && issue.close
event_service.close_issue(issue, current_user)
create_note(issue, commit)
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index b26c7513f5b..8b3d56c2b4c 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -112,7 +112,7 @@ module MergeRequests
merge_requests_for_source_branch.each do |merge_request|
SystemNoteService.change_branch_presence(
- merge_request, merge_request.project, @current_user,
+ merge_request, merge_request.project, @current_user,
:source, @branch_name, presence)
end
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 6975b2ee55b..98a71cbf1ad 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -241,9 +241,14 @@ class SystemNoteService
note_options.merge!(noteable: noteable)
end
- create_note(note_options)
+ if noteable.is_a?(ExternalIssue)
+ noteable.project.issues_tracker.create_cross_reference_note(noteable, mentioner, author)
+ else
+ create_note(note_options)
+ end
end
+
def self.cross_reference?(note_text)
note_text.start_with?(cross_reference_note_prefix)
end
@@ -259,7 +264,7 @@ class SystemNoteService
#
# Returns Boolean
def self.cross_reference_disallowed?(noteable, mentioner)
- return true if noteable.is_a?(ExternalIssue)
+ return true if noteable.is_a?(ExternalIssue) && !noteable.project.jira_tracker_active?
return false unless mentioner.is_a?(MergeRequest)
return false unless noteable.is_a?(Commit)
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8657d2c71fe..531247e9148 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -80,6 +80,10 @@
%span.pull-right
= API::API::version
%p
+ Git
+ %span.pull-right
+ = Gitlab::Git.version
+ %p
Ruby
%span.pull-right
#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index 8358a14445b..741d111fb7d 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -1,6 +1,7 @@
- page_title "Identities", @user.name, "Users"
= render 'admin/users/head'
+= link_to 'New Identity', new_admin_user_identity_path, class: 'pull-right btn btn-new'
- if @identities.present?
.table-holder
%table.table
diff --git a/app/views/admin/identities/new.html.haml b/app/views/admin/identities/new.html.haml
new file mode 100644
index 00000000000..e30bf0ef0ee
--- /dev/null
+++ b/app/views/admin/identities/new.html.haml
@@ -0,0 +1,4 @@
+- page_title "New Identity"
+%h3.page-title New identity
+%hr
+= render 'form'
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index c5fb3c95506..c407972cd08 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -3,7 +3,7 @@
To register a new runner you should enter the following registration token.
With this token the runner will request a unique runner token and use that for future communication.
Registration token is
- %code{ id: 'runners-token' } #{current_application_settings.ensure_runners_registration_token}
+ %code{ id: 'runners-token' } #{current_application_settings.runners_registration_token}
.bs-callout.clearfix
.pull-left
diff --git a/app/views/ci/lints/_create.html.haml b/app/views/ci/lints/_create.html.haml
index 77f78caa8d8..f7875e68b7e 100644
--- a/app/views/ci/lints/_create.html.haml
+++ b/app/views/ci/lints/_create.html.haml
@@ -41,5 +41,3 @@
%i.fa.fa-remove.incorrect-syntax
%b Error:
= @error
-
-
diff --git a/app/views/ci/lints/create.js.haml b/app/views/ci/lints/create.js.haml
deleted file mode 100644
index a96c0b11b6e..00000000000
--- a/app/views/ci/lints/create.js.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-:plain
- $(".results").html("#{escape_javascript(render "create")}") \ No newline at end of file
diff --git a/app/views/ci/lints/show.html.haml b/app/views/ci/lints/show.html.haml
index fb9057e4882..a144c43be47 100644
--- a/app/views/ci/lints/show.html.haml
+++ b/app/views/ci/lints/show.html.haml
@@ -1,27 +1,17 @@
%h2 Check your .gitlab-ci.yml
%hr
-= form_tag ci_lint_path, method: :post, remote: true do
- .control-group
- = label_tag :content, "Content of .gitlab-ci.yml", class: 'control-label'
- .controls
- = text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
+.row
+ = form_tag ci_lint_path, method: :post do
+ .form-group
+ = label_tag :content, 'Content of .gitlab-ci.yml', class: 'control-label text-nowrap'
+ .col-sm-12
+ = text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
+ .col-sm-12
+ .pull-left.prepend-top-10
+ = submit_tag 'Validate', class: 'btn btn-success submit-yml'
- .control-group.clearfix
- .controls.pull-left.prepend-top-10
- = submit_tag "Validate", class: 'btn btn-success submit-yml'
-
-
-%p.text-center.loading
- %i.fa.fa-refresh.fa-spin
-
-.results.prepend-top-20
-
-:javascript
- $(".loading").hide();
- $('form').bind('ajax:beforeSend', function() {
- $(".loading").show();
- });
- $('form').bind('ajax:complete', function() {
- $(".loading").hide();
- });
+.row.prepend-top-20
+ .col-sm-12
+ .results
+ = render partial: 'create' if defined?(@status)
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index 2e77afb7525..f4a3e3162bf 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -1,13 +1,20 @@
= content_for :flash_message do
= render 'shared/project_limit'
+.top-area
+ %ul.left-top-menu
+ = nav_link(page: [dashboard_projects_path, root_path]) do
+ = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
+ Your Projects
+ = nav_link(page: starred_dashboard_projects_path) do
+ = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
+ Starred Projects
+ = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
+ = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
+ Explore Projects
-%ul.center-top-menu
- = nav_link(page: [dashboard_projects_path, root_path]) do
- = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
- Your Projects
- = nav_link(page: starred_dashboard_projects_path) do
- = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
- Starred Projects
- = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
- = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
- Explore Projects
+ .projects-search-form
+ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs', spellcheck: false
+ - if current_user.can_create_project?
+ = link_to new_project_path, class: 'btn btn-green' do
+ %i.fa.fa-plus
+ New Project
diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml
index 44b7efe5232..4316c358dcb 100644
--- a/app/views/dashboard/milestones/show.html.haml
+++ b/app/views/dashboard/milestones/show.html.haml
@@ -1,18 +1,18 @@
- page_title @milestone.title, "Milestones"
- header_title "Milestones", dashboard_milestones_path
-.issuable-details
- .page-title
- .issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- - if @milestone.closed?
- Closed
- - else
- Open
+.detail-page-header
+ .status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
+ - if @milestone.closed?
+ Closed
+ - else
+ Open
+ %span.identifier
Milestone #{@milestone.title}
- .gray-content-block.middle-block
- %h2.issue-title
- = markdown escape_once(@milestone.title), pipeline: :single_line
+.detail-page-description.gray-content-block.second-block
+ %h2.title
+ = markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
.alert.alert-success.prepend-top-default
diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml
index 81a5909e2d2..cea9ffcc748 100644
--- a/app/views/dashboard/projects/_projects.html.haml
+++ b/app/views/dashboard/projects/_projects.html.haml
@@ -1,11 +1,3 @@
.projects-list-holder
- .projects-search-form
- .input-group
- = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
- - if current_user.can_create_project?
- %span.input-group-btn
- = link_to new_project_path, class: 'btn btn-green' do
- %i.fa.fa-plus
- New Project
= render 'shared/projects/list', projects: @projects, ci: true
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb
deleted file mode 100644
index 79d6c761d8f..00000000000
--- a/app/views/devise/mailer/unlock_instructions.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-<p>Hello <%= @resource.email %>!</p>
-
-<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
-
-<p>Click the link below to unlock your account:</p>
-
-<p><%= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token) %></p>
diff --git a/app/views/devise/mailer/unlock_instructions.html.haml b/app/views/devise/mailer/unlock_instructions.html.haml
new file mode 100644
index 00000000000..52b327e20c5
--- /dev/null
+++ b/app/views/devise/mailer/unlock_instructions.html.haml
@@ -0,0 +1,10 @@
+%p
+Hello #{@resource.name}!
+
+%p
+ Your GitLab account has been locked due to an excessive amount of unsuccessful
+ sign in attempts. Your account will automatically unlock in
+ = time_ago_in_words(Devise.unlock_in.from_now)
+ or you may click the link below to unlock now.
+
+%p= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token)
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb
deleted file mode 100644
index f9277d1673f..00000000000
--- a/app/views/devise/unlocks/new.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-<h2>Resend unlock instructions</h2>
-
-<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
- <%= devise_error_messages! %>
-
- <div><%= f.label :email %><br />
- <%= f.email_field :email %></div>
-
- <div><%= f.submit "Resend unlock instructions" %></div>
-<% end %>
-
-<%= render partial: "devise/shared/links" %>
diff --git a/app/views/devise/unlocks/new.html.haml b/app/views/devise/unlocks/new.html.haml
new file mode 100644
index 00000000000..49c087c0646
--- /dev/null
+++ b/app/views/devise/unlocks/new.html.haml
@@ -0,0 +1,14 @@
+.login-box
+ .login-heading
+ %h3 Resend unlock email
+ .login-body
+ = form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
+ .devise-errors
+ = devise_error_messages!
+ .clearfix.append-bottom-20
+ = f.email_field :email, class: 'form-control', placeholder: 'Email', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off'
+ .clearfix
+ = f.submit 'Resend unlock instructions', class: 'btn btn-success'
+
+.clearfix.prepend-top-20
+ = render 'devise/shared/sign_in_link'
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 11d69977ef9..bbafc08435a 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,5 +1,5 @@
-.panel.panel-default.projects-list-holder
- .panel-heading.clearfix
+.projects-list-holder
+ .projects-search-form
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
- if can? current_user, :create_projects, @group
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 350e216fcc6..d063b257b5e 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -1,24 +1,24 @@
- page_title @milestone.title, "Milestones"
= render "header_title"
-.issuable-details
- .page-title
- .issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- - if @milestone.closed?
- Closed
- - else
- Open
+.detail-page-header
+ .status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
+ - if @milestone.closed?
+ Closed
+ - else
+ Open
+ %span.identifier
Milestone #{@milestone.title}
- .pull-right
- - if can?(current_user, :admin_milestones, @group)
- - if @milestone.active?
- = link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
- - else
- = link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
+ .pull-right
+ - if can?(current_user, :admin_milestones, @group)
+ - if @milestone.active?
+ = link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
+ - else
+ = link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- .gray-content-block.middle-block
- %h2.issue-title
- = markdown escape_once(@milestone.title), pipeline: :single_line
+.detail-page-description.gray-content-block.second-block
+ %h2.title
+ = markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
.alert.alert-success.prepend-top-default
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index dc8e81323a6..c2c7c581b3e 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -5,37 +5,47 @@
- if current_user
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
-.dashboard
- .header-with-avatar.clearfix
- = image_tag group_icon(@group), class: "avatar group-avatar s90"
- %h3
- = @group.name
- .username
- @#{@group.path}
- - if @group.description.present?
- .description
- = markdown(@group.description, pipeline: :description)
- %hr
-
- = render 'shared/show_aside'
-
- - if can?(current_user, :read_group, @group)
- .row
- %section.activities.col-md-7
- .hidden-xs
- - if current_user
- = render "events/event_last_push", event: @last_push
- .pull-right
- = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
- %i.fa.fa-rss
-
- = render 'shared/event_filter'
- %hr
-
- .content_list
- = spinner
- %aside.side.col-md-5
- = render "projects", projects: @projects
- - else
- %p
- This group does not have public projects
+.cover-block
+ .avatar-holder
+ = link_to group_icon(@group), target: '_blank' do
+ = image_tag group_icon(@group), class: "avatar group-avatar s90"
+ .cover-title
+ = @group.name
+
+ .cover-desc.username
+ @#{@group.path}
+
+ - if @group.description.present?
+ .cover-desc.description
+ = markdown(@group.description, pipeline: :description)
+
+- if can?(current_user, :read_group, @group)
+ %ul.center-top-menu.no-top
+ %li.active
+ = link_to "#activity", 'data-toggle' => 'tab' do
+ Activity
+ - if @projects.present?
+ %li
+ = link_to "#projects", 'data-toggle' => 'tab' do
+ Projects
+
+ .tab-content
+ .tab-pane.active#activity
+ .gray-content-block.activity-filter-block
+ - if current_user
+ = render "events/event_last_push", event: @last_push
+ .pull-right
+ = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
+ %i.fa.fa-rss
+
+ = render 'shared/event_filter'
+
+ .content_list
+ = spinner
+
+ .tab-pane#projects
+ = render "projects", projects: @projects
+
+- else
+ %p
+ This group does not have public projects
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 27112c6745a..00cb4aa24cc 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,4 +1,2 @@
%div
- "#{link_to @note.author_name, user_url(@note.author)} wrote:"
-%div
= markdown(@note.note, pipeline: :email)
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 20a5b6a66e7..5b7ecce86ab 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -7,6 +7,10 @@
%strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit)
from
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
+ - merge_request = @build.merge_request
+ - if merge_request
+ via
+ = link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request)
#up-build-trace
- if @commit.matrix_for_ref?(@build.ref)
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 634924db247..ddb77fd796b 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -20,8 +20,8 @@
%p
%span.light Commit
- = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace", data: { clipboard_text: @commit.id }
- = clipboard_button
+ = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
+ = clipboard_button(clipboard_text: @commit.id)
.commit-info-row
%span.light Authored by
%strong
@@ -40,7 +40,7 @@
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
-- if @ci_commit && @ci_commit.show_build_status?
+- if @ci_commit
.pull-right
= link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do
= ci_status_icon(@ci_commit)
diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml
index 45a00e4d259..74a05df24d3 100644
--- a/app/views/projects/commit_statuses/_commit_status.html.haml
+++ b/app/views/projects/commit_statuses/_commit_status.html.haml
@@ -19,11 +19,11 @@
- if defined?(commit_sha) && commit_sha
%td
- = link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace"
-
+ = link_to commit_status.short_sha, namespace_project_commit_path(commit_status.project.namespace, commit_status.project, commit_status.sha), class: "monospace"
+
%td
- if commit_status.ref
- = link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref)
+ = link_to commit_status.ref, namespace_project_commits_path(commit_status.project.namespace, commit_status.project, commit_status.ref)
- else
.light none
@@ -66,7 +66,7 @@
%td
.pull-right
- - if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url
+ - if current_user && can?(current_user, :download_build_artifacts, commit_status.project) && commit_status.download_url
= link_to commit_status.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.project)
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 1303b27c4f3..28b82dd31f3 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -17,7 +17,7 @@
%a.text-expander.js-toggle-button ...
.pull-right
- - if ci_commit && ci_commit.show_build_status?
+ - if ci_commit
= render_ci_status(ci_commit)
&nbsp;
= clipboard_button(clipboard_text: commit.id)
diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml
index 3c491c1a8b8..de415ae51a4 100644
--- a/app/views/projects/issues/_closed_by_box.html.haml
+++ b/app/views/projects/issues/_closed_by_box.html.haml
@@ -1,3 +1,2 @@
-.issue-closed-by-widget
- = icon('check')
+.issue-closed-by-widget.gray-content-block.second-block.white
This issue will be closed automatically when merge request #{markdown(merge_requests_sentence(@closed_by_merge_requests), pipeline: :gfm)} is accepted.
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 405bae1bbb9..dc434cf38c4 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,12 +1,9 @@
- content_for :note_actions do
- if can?(current_user, :update_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue'
+ = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue'
- else
- = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close js-note-target-close', title: 'Close Issue'
-
-.gray-content-block.second-block.oneline-block
- = render 'votes/votes_block', votable: @issue
+ = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue'
#notes
= render 'projects/notes/notes_with_form'
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index fe856ac991e..254968e4f67 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -15,9 +15,10 @@
%span.merge-request-info
%strong
= link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title"
- in
- - project = merge_request.target_project
- = link_to project.name_with_namespace, namespace_project_path(project.namespace, project)
+ - unless @issue.project.id == merge_request.target_project.id
+ in
+ - project = merge_request.target_project
+ = link_to project.name_with_namespace, namespace_project_path(project.namespace, project)
%span.merge-request-status.prepend-left-10
- if merge_request.merged?
MERGED
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index cc2cf8c8716..b6efa05a1ae 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -2,60 +2,65 @@
= render "header_title"
.issue
- .issue-details.issuable-details
- .issuable-title
- .issue-box{ class: issue_box_class(@issue) }
+ .detail-page-header
+ .status-box{ class: status_box_class(@issue) }
+ - if @issue.closed?
+ Closed
+ - else
+ Open
+ %span.identifier
+ Issue ##{@issue.iid}
+ %span.creator
+ &middot;
+ opened by #{link_to_member(@project, @issue.author, size: 24)}
+ &middot;
+ = time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
+ - if @issue.updated_at != @issue.created_at
+ %span
+ &middot;
+ = icon('edit', title: 'edited')
+ = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
+
+ .pull-right
+ - if can?(current_user, :create_issue, @project)
+ = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-nr btn-grouped new-issue-link btn-success', title: 'New Issue', id: 'new_issue_link' do
+ = icon('plus')
+ New Issue
+ - if can?(current_user, :update_issue, @issue)
- if @issue.closed?
- Closed
+ = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen'
- else
- Open
- %span.issuable-id Issue ##{@issue.iid}
- %span.creator
- &middot;
- opened by #{link_to_member(@project, @issue.author, size: 24)}
- &middot;
- = time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
- - if @issue.updated_at != @issue.created_at
- %span
- &middot;
- = icon('edit', title: 'edited')
- = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
+ = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close Issue'
- .pull-right
- - if can?(current_user, :create_issue, @project)
- = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-grouped new-issue-link', title: 'New Issue', id: 'new_issue_link' do
- = icon('plus')
- New Issue
- - if can?(current_user, :update_issue, @issue)
- - if @issue.closed?
- = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen'
- - else
- = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close', title: 'Close Issue'
+ = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-nr btn-grouped issuable-edit' do
+ = icon('pencil-square-o')
+ Edit
- = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-grouped issuable-edit' do
- = icon('pencil-square-o')
- Edit
+ .issue-details.issuable-details
+ .detail-page-description.gray-content-block.second-block
+ %h2.title
+ = markdown escape_once(@issue.title), pipeline: :single_line
+ %div
+ - if @issue.description.present?
+ .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
+ .wiki
+ = preserve do
+ = markdown(@issue.description, cache_key: [@issue, "description"])
+ %textarea.hidden.js-task-list-field
+ = @issue.description
- .row
- %section.col-md-9
- .gray-content-block
- %h2.issue-title
- = markdown escape_once(@issue.title), pipeline: :single_line
- %div
- - if @issue.description.present?
- .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
- .wiki
- = preserve do
- = markdown(@issue.description, cache_key: [@issue, "description"])
- %textarea.hidden.js-task-list-field
- = @issue.description
+ .merge-requests
+ = render 'merge_requests'
+
+ .gray-content-block.second-block.oneline-block
+ = render 'votes/votes_block', votable: @issue
- .merge-requests
- = render 'merge_requests'
+ - if @closed_by_merge_requests.present?
+ = render 'projects/issues/closed_by_box'
- - if @closed_by_merge_requests.present?
- = render 'projects/issues/closed_by_box'
- .issue-discussion
+ .row
+ %section.col-md-9
+ .issuable-discussion
= render 'projects/issues/discussion'
%aside.col-md-3
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index 7a7428d35cc..bff3c3b283d 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -1,11 +1,8 @@
- content_for :note_actions do
- if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open?
- = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
+ = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
- if @merge_request.closed?
- = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
-
-.gray-content-block.second-block.oneline-block
- = render 'votes/votes_block', votable: @merge_request
+ = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 4172d5a4e88..a14943b15d3 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -23,15 +23,15 @@
= link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits
%span.badge= @commits.size
- %li.diffs-tab.active
- = link_to url_for(params), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
- Changes
- %span.badge= @diffs.size
- if @ci_commit
%li.builds-tab.active
= link_to url_for(params), data: {target: 'div#builds', action: 'builds', toggle: 'tab'} do
Builds
%span.badge= @statuses.size
+ %li.diffs-tab.active
+ = link_to url_for(params), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
+ Changes
+ %span.badge= @diffs.size
.tab-content
#commits.commits.tab-pane
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 04f8fd74422..e9ffbd06be2 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -5,81 +5,84 @@
- fluid_layout true
.merge-request{'data-url' => merge_request_path(@merge_request)}
- .merge-request-details.issuable-details
- = render "projects/merge_requests/show/mr_title"
- .row
- %section.col-md-9
- = render "projects/merge_requests/show/mr_box"
- .append-bottom-default.mr-source-target.prepend-top-default
- - if @merge_request.open?
- .pull-right
- - if @merge_request.source_branch_exists?
- = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do
- = icon('cloud-download fw')
- Check out branch
+ = render "projects/merge_requests/show/mr_title"
- %span.dropdown
- %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
- = icon('download')
- Download as
- %span.caret
- %ul.dropdown-menu
- %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
- %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- .normal
- %span Request to merge
- %span.label-branch= source_branch_with_namespace(@merge_request)
- %span into
- = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
- = @merge_request.target_branch
+ .merge-request-details.issuable-details
+ = render "projects/merge_requests/show/mr_box"
+ .append-bottom-default.mr-source-target.prepend-top-default
+ - if @merge_request.open?
+ .pull-right
+ - if @merge_request.source_branch_exists?
+ = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do
+ = icon('cloud-download fw')
+ Check out branch
- = render "projects/merge_requests/show/how_to_merge"
- = render "projects/merge_requests/widget/show.html.haml"
+ %span.dropdown
+ %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
+ = icon('download')
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
+ %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
+ .normal
+ %span Request to merge
+ %span.label-branch= source_branch_with_namespace(@merge_request)
+ %span into
+ = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
+ = @merge_request.target_branch
- - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user)
- .light.prepend-top-default
- You can also accept this merge request manually using the
- = succeed '.' do
- = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
+ = render "projects/merge_requests/show/how_to_merge"
+ = render "projects/merge_requests/widget/show.html.haml"
- - if @commits.present?
- %ul.merge-request-tabs.center-top-menu.no-top.no-bottom
- %li.notes-tab
- = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do
- Discussion
- %span.badge= @merge_request.mr_and_commit_notes.user.count
- %li.commits-tab
- = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
- Commits
- %span.badge= @commits.size
- %li.diffs-tab
- = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
- Changes
- %span.badge= @merge_request.diffs.size
- - if @ci_commit
- %li.builds-tab
- = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
- Builds
- %span.badge= @statuses.size
+ - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user)
+ .light.prepend-top-default
+ You can also accept this merge request manually using the
+ = succeed '.' do
+ = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- .tab-content
- #notes.notes.tab-pane.voting_notes
- = render "projects/merge_requests/discussion"
- #commits.commits.tab-pane
- - # This tab is always loaded via AJAX
- #diffs.diffs.tab-pane
- - # This tab is always loaded via AJAX
- #builds.builds.tab-pane
- - # This tab is always loaded via AJAX
+ - if @commits.present?
+ %ul.merge-request-tabs.center-top-menu.no-top.no-bottom
+ %li.notes-tab
+ = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do
+ Discussion
+ %span.badge= @merge_request.mr_and_commit_notes.user.count
+ %li.commits-tab
+ = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
+ Commits
+ %span.badge= @commits.size
+ - if @ci_commit
+ %li.builds-tab
+ = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
+ Builds
+ %span.badge= @statuses.size
+ %li.diffs-tab
+ = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
+ Changes
+ %span.badge= @merge_request.diffs.size
- .mr-loading-status
- = spinner
+ .tab-content
+ #notes.notes.tab-pane.voting_notes
+ .gray-content-block.second-block.oneline-block
+ = render 'votes/votes_block', votable: @merge_request
- %aside.col-md-3
- = render 'shared/issuable/sidebar', issuable: @merge_request
+ .row
+ %section.col-md-9
+ .issuable-discussion
+ = render "projects/merge_requests/discussion"
+ %aside.col-md-3
+ = render 'shared/issuable/sidebar', issuable: @merge_request
+ = render 'shared/show_aside'
- = render 'shared/show_aside'
+ #commits.commits.tab-pane
+ - # This tab is always loaded via AJAX
+ #builds.builds.tab-pane
+ - # This tab is always loaded via AJAX
+ #diffs.diffs.tab-pane
+ - # This tab is always loaded via AJAX
+ .mr-loading-status
+ = spinner
:javascript
var merge_request;
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index 98f0357ce4e..877cc3d744b 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -8,8 +8,8 @@
%p
%strong Step 1.
Fetch and check out the branch for this merge request
- = clipboard_button
- %pre.dark
+ = clipboard_button(clipboard_target: 'pre#merge-info-1')
+ %pre.dark#merge-info-1
- if @merge_request.for_fork?
:preserve
git fetch #{h @merge_request.source_project.http_url_to_repo} #{h @merge_request.source_branch}
@@ -25,8 +25,8 @@
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
- = clipboard_button
- %pre.dark
+ = clipboard_button(clipboard_target: 'pre#merge-info-3')
+ %pre.dark#merge-info-3
- if @merge_request.for_fork?
:preserve
git checkout #{h @merge_request.target_branch}
@@ -38,8 +38,8 @@
%p
%strong Step 4.
Push the result of the merge to GitLab
- = clipboard_button
- %pre.dark
+ = clipboard_button(clipboard_target: 'pre#merge-info-4')
+ %pre.dark#merge-info-4
:preserve
git push origin #{h @merge_request.target_branch}
- unless @merge_request.can_be_merged_by?(current_user)
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 9bfe202589e..0f81e5e8914 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,5 +1,5 @@
-.gray-content-block.middle-block
- %h2.issue-title
+.detail-page-description.gray-content-block.second-block
+ %h2.title
= markdown escape_once(@merge_request.title), pipeline: :single_line
%div
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index d65c3b16618..fc6fb2a0d42 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,7 +1,8 @@
-.issuable-title
- .issue-box{ class: issue_box_class(@merge_request) }
+.detail-page-header
+ .status-box{ class: status_box_class(@merge_request) }
= @merge_request.state_human_name
- %span.issuable-id Merge Request ##{@merge_request.iid}
+ %span.identifier
+ Merge Request ##{@merge_request.iid}
%span.creator
&middot;
opened by #{link_to_member(@project, @merge_request.author, size: 24)}
@@ -16,9 +17,9 @@
.issue-btn-group.pull-right
- if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open?
- = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
- = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do
+ = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close merge request'
+ = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do
%i.fa.fa-pencil-square-o
Edit
- if @merge_request.closed?
- = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
+ = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request'
diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml
index 6f52c963a53..d1d602eecdc 100644
--- a/app/views/projects/merge_requests/widget/_merged.html.haml
+++ b/app/views/projects/merge_requests/widget/_merged.html.haml
@@ -8,19 +8,15 @@
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
%div
- if !@merge_request.source_branch_exists? || (params[:delete_source] == 'true')
- = succeed '.' do
- The changes were merged into
- = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
- = @merge_request.target_branch
+ The changes were merged into
+ #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}.
The source branch has been removed.
- elsif @merge_request.can_remove_source_branch?(current_user)
.remove_source_branch_widget
%p
- = succeed '.' do
- The changes were merged into
- = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
- = @merge_request.target_branch
+ The changes were merged into
+ #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}.
You can remove the source branch now.
= link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request.source_branch), remote: true, method: :delete, class: "btn btn-primary btn-sm remove_source_branch" do
%i.fa.fa-times
diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml
index c6bc4ca5beb..d9a1730a8bc 100644
--- a/app/views/projects/merge_requests/widget/open/_accept.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml
@@ -7,13 +7,13 @@
.accept-action
- if @ci_commit && @ci_commit.active?
%span.btn-group
- = link_to "#", class: "btn btn-create merge_when_build_succeeds" do
+ = button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do
Merge When Build Succeeds
- %a.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' }
+ = button_tag class: "btn btn-success dropdown-toggle", 'data-toggle' => 'dropdown' do
%span.caret
%span.sr-only
Select Merge Moment
- %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' }
+ %ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' }
%li
= link_to "#", class: "merge_when_build_succeeds" do
= icon('check fw')
@@ -23,7 +23,7 @@
= icon('warning fw')
Merge Immediately
- else
- = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do
+ = f.button class: "btn btn-create btn-grouped js-merge-button accept_merge_request #{status_class}" do
Accept Merge Request
- if @merge_request.can_remove_source_branch?(current_user)
.accept-control.checkbox
@@ -42,21 +42,19 @@
= hidden_field_tag :merge_when_build_succeeds, "", autocomplete: "off"
:javascript
- $('.accept_merge_request').on('click', function() {
- $(this).html("<i class='fa fa-spinner fa-spin'></i> Merge in progress");
- });
-
$('.accept-mr-form').on('ajax:send', function() {
$(".accept-mr-form :input").disable();
});
- $('a.accept_merge_request').on('click', function(e) {
- e.preventDefault();
- $(this).closest("form").submit();
+ $('.accept_merge_request').on('click', function() {
+ $('.js-merge-button').html("<i class='fa fa-spinner fa-spin'></i> Merge in progress");
});
- $('a.merge_when_build_succeeds').on('click', function(e) {
- e.preventDefault();
+ $('.merge_when_build_succeeds').on('click', function() {
$("#merge_when_build_succeeds").val("1");
+ });
+
+ $('.js-merge-dropdown a').on('click', function(e) {
+ e.preventDefault();
$(this).closest("form").submit();
});
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 7ecee440337..7e73ae274e9 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,44 +1,44 @@
- page_title @milestone.title, "Milestones"
= render "header_title"
-.issuable-details
- .page-title
- .issue-box{ class: issue_box_class(@milestone) }
- - if @milestone.closed?
- Closed
- - elsif @milestone.expired?
- Expired
- - else
- Open
+.detail-page-header
+ .status-box{ class: status_box_class(@milestone) }
+ - if @milestone.closed?
+ Closed
+ - elsif @milestone.expired?
+ Expired
+ - else
+ Open
+ %span.identifier
Milestone ##{@milestone.iid}
- - if @milestone.expires_at
- %span.creator
- &middot;
- = @milestone.expires_at
- .pull-right
- - if can?(current_user, :admin_milestone, @project)
- = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do
- %i.fa.fa-pencil-square-o
- Edit
+ - if @milestone.expires_at
+ %span.creator
+ &middot;
+ = @milestone.expires_at
+ .pull-right
+ - if can?(current_user, :admin_milestone, @project)
+ - if @milestone.active?
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
+ - else
+ = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
- - if @milestone.active?
- = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
- - else
- = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
+ = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do
+ %i.fa.fa-trash-o
+ Delete
- = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do
- %i.fa.fa-trash-o
- Delete
+ = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do
+ %i.fa.fa-pencil-square-o
+ Edit
- .gray-content-block.middle-block
- %h2.issue-title
- = markdown escape_once(@milestone.title), pipeline: :single_line
- %div
- - if @milestone.description.present?
- .description
- .wiki
- = preserve do
- = markdown @milestone.description
+.detail-page-description.gray-content-block.second-block
+ %h2.title
+ = markdown escape_once(@milestone.title), pipeline: :single_line
+ %div
+ - if @milestone.description.present?
+ .description
+ .wiki
+ = preserve do
+ = markdown @milestone.description
- if @milestone.issues.any? && @milestone.can_be_closed?
.alert.alert-success.prepend-top-default
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 88e711ab534..acb6dc52a8e 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -13,6 +13,6 @@
.error-alert
.note-form-actions.clearfix
- = f.submit 'Add Comment', class: "btn btn-create comment-btn btn-grouped js-comment-button"
+ = f.submit 'Add Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button"
= yield(:note_actions)
%a.btn.btn-cancel.js-close-discussion-note-form Cancel
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index 99c1b0fa43e..eb378b42603 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -7,4 +7,4 @@
= render "projects/notes/form", view: diff_view
:javascript
- new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")
+ var notes = new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 9c7a5584da9..7466a098e24 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -71,7 +71,7 @@
= render default_project_view
- if current_user
- - access = user_max_access_in_project(current_user, @project)
+ - access = user_max_access_in_project(current_user.id, @project)
- if access
.prepend-top-20.project-footer
.gray-content-block.footer-block.center
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index cefe33e581f..89b072cea92 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -20,16 +20,24 @@
%li
= link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do
= icon('pencil fw')
- Create file
+ New file
%li
= link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do
= icon('file fw')
Upload file
- %li.divider
%li
= link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do
= icon('folder fw')
New directory
+ %li.divider
+ %li
+ = link_to new_namespace_project_branch_path(@project.namespace, @project) do
+ = icon('code-fork fw')
+ New branch
+ %li
+ = link_to new_namespace_project_tag_path(@project.namespace, @project) do
+ = icon('tags fw')
+ New tag
- elsif !on_top_of_branch?
%li
%span.btn.btn-sm.add-to-tree.disabled.has_tooltip{title: "You can only add files when you are on a branch.", data: {container: 'body'}}
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index ce8ddff9556..45d700781f3 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -6,7 +6,7 @@
- if issue.description.present?
.description.term
= preserve do
- = search_md_sanitize(markdown(issue.description))
+ = search_md_sanitize(markdown(issue.description, { project: issue.project }))
%span.light
#{issue.project.name_with_namespace}
- if issue.closed?
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 91ccd1ef660..90dc0062481 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -19,7 +19,7 @@
- else
Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a
<strong>Work In Progress</strong> merge request from being merged before it's ready.
-.form-group.issuable-description
+.form-group.detail-page-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 0019f739b89..79c5cc7f40a 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -1,13 +1,5 @@
.issuable-sidebar.issuable-affix
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
- .block
- .title
- Cross-project reference
- .cross-project-reference
- %span#cross-project-reference
- = cross_project_reference(@project, issuable)
- = clipboard_button(clipboard_target: 'span#cross-project-reference')
-
.block.assignee
.title
%label
@@ -62,6 +54,14 @@
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
+ .block
+ .title
+ Cross-project reference
+ .cross-project-reference
+ %span#cross-project-reference
+ = cross_project_reference(@project, issuable)
+ = clipboard_button(clipboard_target: 'span#cross-project-reference')
+
= render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 669e6119fb6..aa5acee9c14 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -1,25 +1,25 @@
-.issuable-details
- .page-title
- .snippet-box.has_tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }}
- = visibility_level_icon(@snippet.visibility_level, fw: false)
- = visibility_level_label(@snippet.visibility_level)
+.detail-page-header
+ .snippet-box.has_tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }}
+ = visibility_level_icon(@snippet.visibility_level, fw: false)
+ = visibility_level_label(@snippet.visibility_level)
+ %span.identifier
Snippet ##{@snippet.id}
- %span.creator
- &middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
- &middot;
- = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
- - if @snippet.updated_at != @snippet.created_at
- %span
- &middot;
- = icon('edit', title: 'edited')
- = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
+ %span.creator
+ &middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
+ &middot;
+ = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
+ - if @snippet.updated_at != @snippet.created_at
+ %span
+ &middot;
+ = icon('edit', title: 'edited')
+ = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
- .pull-right
- - if @snippet.project_id?
- = render "projects/snippets/actions"
- - else
- = render "snippets/actions"
+ .pull-right
+ - if @snippet.project_id?
+ = render "projects/snippets/actions"
+ - else
+ = render "snippets/actions"
- .gray-content-block.middle-block
- %h2.issue-title
- = markdown escape_once(@snippet.title), pipeline: :single_line
+.detail-page-description.gray-content-block.second-block
+ %h2.title
+ = markdown escape_once(@snippet.title), pipeline: :single_line
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index a0a6e2d9810..b7a7eb4e6f7 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -73,7 +73,7 @@
.user-calendar-activities
-%ul.center-top-menu.no-top.no-bottom.bottom-border
+%ul.center-top-menu.no-top.no-bottom.bottom-border.wide
%li.active
= link_to "#activity", 'data-toggle' => 'tab' do
Activity
diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml
index 65d3f4c7faf..e16187bb42f 100644
--- a/app/views/votes/_votes_block.html.haml
+++ b/app/views/votes/_votes_block.html.haml
@@ -11,19 +11,20 @@
= icon('smile-o')
.emoji-menu
.emoji-menu-content
+ = text_field_tag :emoji_search, "", class: "emoji-search search-input form-control"
- AwardEmoji.emoji_by_category.each do |category, emojis|
- %h4= AwardEmoji::CATEGORIES[category]
+ %h5= AwardEmoji::CATEGORIES[category]
%ul
- emojis.each do |emoji|
%li
- = emoji_icon(emoji["name"], emoji["unicode"])
+ = emoji_icon(emoji["name"], emoji["unicode"], emoji["aliases"])
- if current_user
:coffeescript
post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"
noteable_type = "#{votable.class.name.underscore}"
noteable_id = "#{votable.id}"
- aliases = #{AwardEmoji::ALIASES.to_json}
+ aliases = #{AwardEmoji.aliases.to_json}
window.awards_handler = new AwardsHandler(
post_emoji_url,
@@ -32,11 +33,11 @@
aliases
)
- $(".emoji-menu-content li").click (e)->
+ $(".awards").on "click", ".emoji-menu-content li", (e) ->
emoji = $(this).find(".emoji-icon").data("emoji")
awards_handler.addAward(emoji)
- $(".awards").on "click", ".award", (e)->
+ $(".awards").on "click", ".award", (e) ->
emoji = $(this).find(".icon").data("emoji")
awards_handler.addAward(emoji)
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index db378118f85..db68b5512b8 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -144,6 +144,15 @@ production: &base
# plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
# ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
+ ## Auxiliary jobs
+ # Periodically executed jobs, to self-heal Gitlab, do external synchronizations, etc.
+ # Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
+ cron_jobs:
+ # Flag stuck CI builds as failed
+ stuck_ci_builds_worker:
+ cron: "0 0 * * *"
+
+
#
# 2. GitLab CI settings
# ==========================
@@ -287,6 +296,15 @@ production: &base
# arguments, followed by optional 'args' which can be either a hash or an array.
# Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
providers:
+ # See omniauth-cas3 for more configuration details
+ # - { name: 'cas3',
+ # label: 'cas3',
+ # args: {
+ # url: 'https://sso.example.com',
+ # disable_ssl_verification: false,
+ # login_url: '/cas/login',
+ # service_validate_url: '/cas/p3/serviceValidate',
+ # logout_url: '/cas/logout'} }
# - { name: 'github',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET',
@@ -324,6 +342,10 @@ production: &base
# application_name: 'YOUR_APP_NAME',
# application_password: 'YOUR_APP_PASSWORD' } }
+ # SSO maximum session duration in seconds. Defaults to CAS default of 8 hours.
+ # cas3:
+ # session_duration: 28800
+
# Shared file storage settings
shared:
# path: /mnt/gitlab # Default: shared
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 63d8ae17436..816cb0c02a9 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -126,6 +126,10 @@ Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
Settings.omniauth['providers'] ||= []
+Settings.omniauth['cas3'] ||= Settingslogic.new({})
+Settings.omniauth.cas3['session_duration'] ||= 8.hours
+Settings.omniauth['session_tickets'] ||= Settingslogic.new({})
+Settings.omniauth.session_tickets['cas3'] = 'ticket'
Settings['shared'] ||= Settingslogic.new({})
Settings.shared['path'] = File.expand_path(Settings.shared['path'] || "shared", Rails.root)
@@ -164,7 +168,7 @@ Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].
Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
-Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
+Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z]*-\d*))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab['max_attachment_size'] ||= 10
@@ -225,6 +229,15 @@ Settings.gravatar['ssl_url'] ||= 'https://secure.gravatar.com/avatar/%{hash}?
Settings.gravatar['host'] = Settings.get_host_without_www(Settings.gravatar['plain_url'])
#
+# Cron Jobs
+#
+Settings['cron_jobs'] ||= Settingslogic.new({})
+Settings.cron_jobs['stuck_ci_builds_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['stuck_ci_builds_worker']['cron'] ||= '0 0 * * *'
+Settings.cron_jobs['stuck_ci_builds_worker']['job_class'] = 'StuckCiBuildsWorker'
+
+
+#
# GitLab Shell
#
Settings['gitlab_shell'] ||= Settingslogic.new({})
diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb
index bfb8656df55..df28d30d750 100644
--- a/config/initializers/carrierwave.rb
+++ b/config/initializers/carrierwave.rb
@@ -31,11 +31,11 @@ if File.exists?(aws_file)
if Rails.env.test?
Fog.mock!
connection = ::Fog::Storage.new(
- aws_access_key_id: AWS_CONFIG['access_key_id'],
- aws_secret_access_key: AWS_CONFIG['secret_access_key'],
- provider: 'AWS',
- region: AWS_CONFIG['region']
- )
+ aws_access_key_id: AWS_CONFIG['access_key_id'],
+ aws_secret_access_key: AWS_CONFIG['secret_access_key'],
+ provider: 'AWS',
+ region: AWS_CONFIG['region']
+ )
connection.directories.create(key: AWS_CONFIG['bucket'])
end
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 5fb43a86e13..d82cfb3ec0c 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -121,14 +121,14 @@ Devise.setup do |config|
config.lock_strategy = :failed_attempts
# Defines which key will be used when locking and unlocking an account
- # config.unlock_keys = [ :email ]
+ config.unlock_keys = [ :email ]
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
- config.unlock_strategy = :time
+ config.unlock_strategy = :both
# Number of authentication tries before locking an account if lock_strategy
# is failed attempts.
@@ -241,6 +241,16 @@ Devise.setup do |config|
# An Array from the configuration will be expanded.
provider_arguments.concat provider['args']
when Hash
+ # Add procs for handling SLO
+ if provider['name'] == 'cas3'
+ provider['args'][:on_single_sign_out] = lambda do |request|
+ ticket = request.params[:session_index]
+ raise "Service Ticket not found." unless Gitlab::OAuth::Session.valid?(:cas3, ticket)
+ Gitlab::OAuth::Session.destroy(:cas3, ticket)
+ true
+ end
+ end
+
# A Hash from the configuration will be passed as is.
provider_arguments << provider['args'].symbolize_keys
end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 2e3a71912ef..dcf6ce74d96 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -18,11 +18,12 @@ Sidekiq.configure_server do |config|
chain.add Gitlab::SidekiqMiddleware::MemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS']
end
- # Sidekiq-cron: load recurring jobs from schedule.yml
- schedule_file = 'config/schedule.yml'
- if File.exists?(schedule_file)
- Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
- end
+ # Sidekiq-cron: load recurring jobs from gitlab.yml
+ # UGLY Hack to get nested hash from settingslogic
+ cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json)
+ # UGLY hack: Settingslogic doesn't allow 'class' key
+ cron_jobs.each { |k,v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') }
+ Sidekiq::Cron::Job.load_from_hash! cron_jobs
# Database pool should be at least `sidekiq_concurrency` + 2
# For more info, see: https://github.com/mperham/sidekiq/blob/master/4.0-Upgrade.md
diff --git a/config/routes.rb b/config/routes.rb
index e2d4fcb65a8..b9242327de1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -188,7 +188,7 @@ Rails.application.routes.draw do
namespace :admin do
resources :users, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do
resources :keys, only: [:show, :destroy]
- resources :identities, only: [:index, :edit, :update, :destroy]
+ resources :identities, except: [:show]
delete 'stop_impersonation' => 'impersonation#destroy', on: :collection
@@ -441,7 +441,7 @@ Rails.application.routes.draw do
scope do
post(
- '/create_dir/*id',
+ '/create_dir/*id',
to: 'tree#create_dir',
constraints: { id: /.+/ },
as: 'create_dir'
diff --git a/config/schedule.yml b/config/schedule.yml
deleted file mode 100644
index 993a95fef56..00000000000
--- a/config/schedule.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Here is a list of jobs that are scheduled to run periodically.
-# We use a UNIX cron notation to specify execution schedule.
-#
-# Please read here for more information:
-# https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
-
-stuck_ci_builds_worker:
- cron: "0 0 * * *"
- class: "StuckCiBuildsWorker"
- queue: "default"
diff --git a/db/migrate/20151012173029_set_jira_service_api_url.rb b/db/migrate/20151012173029_set_jira_service_api_url.rb
new file mode 100644
index 00000000000..2af99e0db0b
--- /dev/null
+++ b/db/migrate/20151012173029_set_jira_service_api_url.rb
@@ -0,0 +1,50 @@
+class SetJiraServiceApiUrl < ActiveRecord::Migration
+ # This migration can be performed online without errors, but some Jira API calls may be missed
+ # when doing so because api_url is not yet available.
+
+ def build_api_url_from_project_url(project_url, api_version)
+ # this is the exact logic previously used to build the Jira API URL from project_url
+ server = URI(project_url)
+ default_ports = [80, 443].include?(server.port)
+ server_url = "#{server.scheme}://#{server.host}"
+ server_url.concat(":#{server.port}") unless default_ports
+ "#{server_url}/rest/api/#{api_version}"
+ end
+
+ def get_api_version_from_api_url(api_url)
+ match = /\/rest\/api\/(?<api_version>\w+)$/.match(api_url)
+ match && match['api_version']
+ end
+
+ def change
+ reversible do |dir|
+ select_all("SELECT id, properties FROM services WHERE services.type IN ('JiraService')").each do |jira_service|
+ id = jira_service["id"]
+ properties = JSON.parse(jira_service["properties"])
+ properties_was = properties.clone
+
+ dir.up do
+ # remove api_version and set api_url
+ if properties['api_version'].present? && properties['project_url'].present?
+ begin
+ properties['api_url'] ||= build_api_url_from_project_url(properties['project_url'], properties['api_version'])
+ rescue
+ # looks like project_url was not a valid URL. Do nothing.
+ end
+ end
+ properties.delete('api_version') if properties.include?('api_version')
+ end
+
+ dir.down do
+ # remove api_url and set api_version (default to '2')
+ properties['api_version'] ||= get_api_version_from_api_url(properties['api_url']) || '2'
+ properties.delete('api_url') if properties.include?('api_url')
+ end
+
+ if properties != properties_was
+ execute("UPDATE services SET properties = '#{quote_string(properties.to_json)}' WHERE id = #{id}")
+ end
+ end
+ end
+ end
+end
diff --git a/db/migrate/20151203162134_add_build_events_to_services.rb b/db/migrate/20151203162134_add_build_events_to_services.rb
index a84be7db3f1..c5542cb864d 100644
--- a/db/migrate/20151203162134_add_build_events_to_services.rb
+++ b/db/migrate/20151203162134_add_build_events_to_services.rb
@@ -1,5 +1,5 @@
class AddBuildEventsToServices < ActiveRecord::Migration
- def up
+ def change
add_column :services, :build_events, :boolean, default: false, null: false
add_column :web_hooks, :build_events, :boolean, default: false, null: false
end
diff --git a/db/migrate/20151209144329_migrate_ci_web_hooks.rb b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
index 825ba1973ff..d7e196e6763 100644
--- a/db/migrate/20151209144329_migrate_ci_web_hooks.rb
+++ b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
@@ -10,4 +10,7 @@ class MigrateCiWebHooks < ActiveRecord::Migration
'JOIN projects ON ci_projects.gitlab_id = projects.id'
)
end
+
+ def down
+ end
end
diff --git a/db/migrate/20151210030143_add_unlock_token_to_user.rb b/db/migrate/20151210030143_add_unlock_token_to_user.rb
new file mode 100644
index 00000000000..0ea66ba65df
--- /dev/null
+++ b/db/migrate/20151210030143_add_unlock_token_to_user.rb
@@ -0,0 +1,5 @@
+class AddUnlockTokenToUser < ActiveRecord::Migration
+ def change
+ add_column :users, :unlock_token, :string
+ end
+end
diff --git a/db/migrate/20151210125928_add_ci_to_project.rb b/db/migrate/20151210125928_add_ci_to_project.rb
index 8a65abab636..8c167f64a2b 100644
--- a/db/migrate/20151210125928_add_ci_to_project.rb
+++ b/db/migrate/20151210125928_add_ci_to_project.rb
@@ -1,5 +1,5 @@
class AddCiToProject < ActiveRecord::Migration
- def up
+ def change
add_column :projects, :ci_id, :integer
add_column :projects, :builds_enabled, :boolean, default: true, null: false
add_column :projects, :shared_runners_enabled, :boolean, default: true, null: false
diff --git a/db/migrate/20151210125929_add_project_id_to_ci.rb b/db/migrate/20151210125929_add_project_id_to_ci.rb
index 5d1cf543576..84273591fa2 100644
--- a/db/migrate/20151210125929_add_project_id_to_ci.rb
+++ b/db/migrate/20151210125929_add_project_id_to_ci.rb
@@ -1,5 +1,5 @@
class AddProjectIdToCi < ActiveRecord::Migration
- def up
+ def change
add_column :ci_builds, :gl_project_id, :integer
add_column :ci_runner_projects, :gl_project_id, :integer
add_column :ci_triggers, :gl_project_id, :integer
diff --git a/db/migrate/20151210125930_migrate_ci_to_project.rb b/db/migrate/20151210125930_migrate_ci_to_project.rb
index 7dfe05174ee..c32c7feb193 100644
--- a/db/migrate/20151210125930_migrate_ci_to_project.rb
+++ b/db/migrate/20151210125930_migrate_ci_to_project.rb
@@ -14,6 +14,10 @@ class MigrateCiToProject < ActiveRecord::Migration
migrate_ci_service
end
+ def down
+ # We can't reverse the data
+ end
+
def migrate_project_id_for_table(table)
subquery = "SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = #{table}.project_id"
execute("UPDATE #{table} SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
@@ -26,7 +30,8 @@ class MigrateCiToProject < ActiveRecord::Migration
def migrate_project_column(column, new_column = nil)
new_column ||= column
- subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id"
+ subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id " \
+ 'ORDER BY ci_projects.updated_at DESC LIMIT 1'
execute("UPDATE projects SET #{new_column}=(#{subquery}) WHERE (#{subquery}) IS NOT NULL")
end
diff --git a/db/migrate/20151210125931_add_index_to_ci_tables.rb b/db/migrate/20151210125931_add_index_to_ci_tables.rb
index 9fedb5d612c..5e129c9303d 100644
--- a/db/migrate/20151210125931_add_index_to_ci_tables.rb
+++ b/db/migrate/20151210125931_add_index_to_ci_tables.rb
@@ -1,5 +1,5 @@
class AddIndexToCiTables < ActiveRecord::Migration
- def up
+ def change
add_index :ci_builds, :gl_project_id
add_index :ci_runner_projects, :gl_project_id
add_index :ci_triggers, :gl_project_id
diff --git a/db/migrate/20151210125932_drop_null_for_ci_tables.rb b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
index 0b007430b0c..c520c2ed56f 100644
--- a/db/migrate/20151210125932_drop_null_for_ci_tables.rb
+++ b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
@@ -1,5 +1,5 @@
class DropNullForCiTables < ActiveRecord::Migration
- def up
+ def change
remove_index :ci_variables, :project_id
remove_index :ci_runner_projects, :project_id
change_column_null :ci_triggers, :project_id, true
diff --git a/db/migrate/20151224123230_rename_emojis.rb b/db/migrate/20151224123230_rename_emojis.rb
new file mode 100644
index 00000000000..62d921dfdcc
--- /dev/null
+++ b/db/migrate/20151224123230_rename_emojis.rb
@@ -0,0 +1,15 @@
+# Migration type: online without errors (works on previous version and new one)
+class RenameEmojis < ActiveRecord::Migration
+ def up
+ # Renames aliases to main names
+ execute("UPDATE notes SET note ='thumbsup' WHERE is_award = true AND note = '+1'")
+ execute("UPDATE notes SET note ='thumbsdown' WHERE is_award = true AND note = '-1'")
+ execute("UPDATE notes SET note ='poop' WHERE is_award = true AND note = 'shit'")
+ end
+
+ def down
+ execute("UPDATE notes SET note ='+1' WHERE is_award = true AND note = 'thumbsup'")
+ execute("UPDATE notes SET note ='-1' WHERE is_award = true AND note = 'thumbsdown'")
+ execute("UPDATE notes SET note ='shit' WHERE is_award = true AND note = 'poop'")
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0167e30ff8b..0d53105b057 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20151210125932) do
+ActiveRecord::Schema.define(version: 20151224123230) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -837,6 +837,7 @@ ActiveRecord::Schema.define(version: 20151210125932) do
t.integer "consumed_timestep"
t.integer "layout", default: 0
t.boolean "hide_project_limit", default: false
+ t.string "unlock_token"
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/README.md b/doc/README.md
index a3098094210..8bac00f2f23 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -7,6 +7,7 @@
- [GitLab Basics](gitlab-basics/README.md) Find step by step how to start working on your commandline and on GitLab.
- [Importing to GitLab](workflow/importing/README.md).
- [Markdown](markdown/markdown.md) GitLab's advanced formatting system.
+- [Migrating from SVN](migration/README.md) Convert a SVN repository to Git and GitLab
- [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do.
- [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 1a524400627..0ca81ffd49e 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -58,6 +58,7 @@ Parameters:
"path": "diaspora-client",
"path_with_namespace": "diaspora/diaspora-client",
"issues_enabled": true,
+ "open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
@@ -100,6 +101,7 @@ Parameters:
"path": "puppet",
"path_with_namespace": "brightbox/puppet",
"issues_enabled": true,
+ "open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
@@ -116,6 +118,16 @@ Parameters:
"path": "brightbox",
"updated_at": "2013-09-30T13:46:02Z"
},
+ "permissions": {
+ "project_access": {
+ "access_level": 10,
+ "notification_level": 3
+ },
+ "group_access": {
+ "access_level": 50,
+ "notification_level": 3
+ }
+ },
"archived": false,
"avatar_url": null
}
@@ -137,6 +149,21 @@ Parameters:
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
+### List starred projects
+
+Get a list of projects which are starred by the authenticated user.
+
+```
+GET /projects/starred
+```
+
+Parameters:
+
+- `archived` (optional) - if passed, limit by archived status
+- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
+- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
+- `search` (optional) - Return list of authorized projects according to a search criteria
+
### List ALL projects
Get a list of all GitLab projects (admin only).
@@ -189,6 +216,7 @@ Parameters:
"path": "diaspora-project-site",
"path_with_namespace": "diaspora/diaspora-project-site",
"issues_enabled": true,
+ "open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 5d9d7a81db3..965b007bedb 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -24,6 +24,7 @@
### Examples
++ [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
+ [Test and deploy Ruby applications to Heroku](examples/test-and-deploy-ruby-application-to-heroku.md)
+ [Test and deploy Python applications to Heroku](examples/test-and-deploy-python-application-to-heroku.md)
+ [Test Clojure applications](examples/test-clojure-application.md)
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 8d4bd44053e..31458d61674 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -1,11 +1,11 @@
# Using Docker Images
-GitLab CI in conjuction with [GitLab Runner](../runners/README.md) can use
+GitLab CI in conjunction with [GitLab Runner](../runners/README.md) can use
[Docker Engine](https://www.docker.com/) to test and build any application.
Docker is an open-source project that allows you to use predefined images to
run applications in independent "containers" that are run within a single Linux
-instance. [Docker Hub][hub] has a rich database of prebuilt images that can be
+instance. [Docker Hub][hub] has a rich database of pre-built images that can be
used to test and build your applications.
Docker, when used with GitLab CI, runs each build in a separate and isolated
@@ -136,6 +136,24 @@ Look for the `[runners.docker]` section:
The image and services defined this way will be added to all builds run by
that runner.
+## Define an image from a private Docker registry
+
+Starting with GitLab Runner 0.6.0, you are able to define images located to
+private registries that could also require authentication.
+
+All you have to do is be explicit on the image definition in `.gitlab-ci.yml`.
+
+```yaml
+image: my.registry.tld:5000/namepace/image:tag
+```
+
+In the example above, GitLab Runner will look at `my.registry.tld:5000` for the
+image `namespace/image:tag`.
+
+If the repository is private you need to authenticate your GitLab Runner in the
+registry. Learn how to do that on
+[GitLab Runner's documentation][runner-priv-reg].
+
## Accessing the services
Let's say that you need a Wordpress instance to test some API integration with
@@ -258,3 +276,4 @@ creation.
[tutum/wordpress]: https://registry.hub.docker.com/u/tutum/wordpress/
[postgres-hub]: https://registry.hub.docker.com/u/library/postgres/
[mysql-hub]: https://registry.hub.docker.com/u/library/mysql/
+[runner-priv-reg]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 022afb70042..b99ea25a3fe 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -27,7 +27,6 @@ The API_TOKEN will take the Secure Variable value: `SECURE`.
| **CI_BUILD_TAG** | 0.5 | The commit tag name. Present only when building tags. |
| **CI_BUILD_NAME** | 0.5 | The name of the build as defined in `.gitlab-ci.yml` |
| **CI_BUILD_STAGE** | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
-| **CI_BUILD_BEFORE_SHA** | all | The first commit that were included in push request |
| **CI_BUILD_REF_NAME** | all | The branch or tag name for which project is built |
| **CI_BUILD_ID** | all | The unique id of the current build that GitLab CI uses internally |
| **CI_BUILD_REPO** | all | The URL to clone the Git repository |
@@ -40,7 +39,6 @@ The API_TOKEN will take the Secure Variable value: `SECURE`.
Example values:
```bash
-export CI_BUILD_BEFORE_SHA="9df57456fa9de2a6d335ca5edf9750ed812b9df0"
export CI_BUILD_ID="50"
export CI_BUILD_REF="1ecfd275763eff1d6b4844ea3168962458c9f27a"
export CI_BUILD_REF_NAME="master"
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 7e2edb945da..fd0d49de4e4 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1,9 +1,12 @@
# Configuration of your builds with .gitlab-ci.yml
-From version 7.12, GitLab CI uses a [YAML](https://en.wikipedia.org/wiki/YAML) file (**.gitlab-ci.yml**) for the project configuration.
-It is placed in the root of your repository and contains definitions of how your project should be built.
-The YAML file defines a set of jobs with constraints stating when they should be run.
-The jobs are defined as top-level elements with a name and always have to contain the `script` clause:
+From version 7.12, GitLab CI uses a [YAML](https://en.wikipedia.org/wiki/YAML)
+file (`.gitlab-ci.yml`) for the project configuration. It is placed in the root
+of your repository and contains definitions of how your project should be built.
+
+The YAML file defines a set of jobs with constraints stating when they should
+be run. The jobs are defined as top-level elements with a name and always have
+to contain the `script` clause:
```yaml
job1:
@@ -13,15 +16,21 @@ job2:
script: "execute-script-for-job2"
```
-The above example is the simplest possible CI configuration with two separate jobs,
-where each of the jobs executes a different command.
-Of course a command can execute code directly (`./configure;make;make install`) or run a script (`test.sh`) in the repository.
+The above example is the simplest possible CI configuration with two separate
+jobs, where each of the jobs executes a different command.
+
+Of course a command can execute code directly (`./configure;make;make install`)
+or run a script (`test.sh`) in the repository.
-Jobs are used to create builds, which are then picked up by [runners](../runners/README.md) and executed within the environment of the runner.
-What is important, is that each job is run independently from each other.
+Jobs are used to create builds, which are then picked up by
+[runners](../runners/README.md) and executed within the environment of the
+runner. What is important, is that each job is run independently from each
+other.
## .gitlab-ci.yml
-The YAML syntax allows for using more complex job specifications than in the above example:
+
+The YAML syntax allows for using more complex job specifications than in the
+above example:
```yaml
image: ruby:2.1
@@ -46,26 +55,31 @@ job1:
- docker
```
-There are a few `keywords` that can't be used as job names:
+There are a few reserved `keywords` that **cannot** be used as job names:
-| keyword | required | description |
+| Keyword | Required | Description |
|---------------|----------|-------------|
-| image | optional | Use docker image, covered in [Use Docker](../docker/README.md) |
-| services | optional | Use docker services, covered in [Use Docker](../docker/README.md) |
-| stages | optional | Define build stages |
-| types | optional | Alias for `stages` |
-| before_script | optional | Define commands prepended for each job's script |
-| variables | optional | Define build variables |
-| cache | optional | Define list of files that should be cached between subsequent runs |
+| image | no | Use docker image, covered in [Use Docker](../docker/README.md) |
+| services | no | Use docker services, covered in [Use Docker](../docker/README.md) |
+| stages | no | Define build stages |
+| types | no | Alias for `stages` |
+| before_script | no | Define commands that run before each job's script |
+| variables | no | Define build variables |
+| cache | no | Define list of files that should be cached between subsequent runs |
### image and services
-This allows to specify a custom Docker image and a list of services that can be used for time of the build.
-The configuration of this feature is covered in separate document: [Use Docker](../docker/README.md).
+
+This allows to specify a custom Docker image and a list of services that can be
+used for time of the build. The configuration of this feature is covered in
+separate document: [Use Docker](../docker/README.md).
### before_script
-`before_script` is used to define the command that should be run before all builds, including deploy builds. This can be an array or a multiline string.
+
+`before_script` is used to define the command that should be run before all
+builds, including deploy builds. This can be an array or a multi-line string.
### stages
+
`stages` is used to define build stages that can be used by jobs.
The specification of `stages` allows for having flexible multi stage pipelines.
@@ -75,7 +89,8 @@ The ordering of elements in `stages` defines the ordering of builds' execution:
1. Builds of next stage are run after success.
Let's consider the following example, which defines 3 stages:
-```
+
+```yaml
stages:
- build
- test
@@ -86,21 +101,26 @@ stages:
1. If all jobs of `build` succeeds, the `test` jobs are executed in parallel.
1. If all jobs of `test` succeeds, the `deploy` jobs are executed in parallel.
1. If all jobs of `deploy` succeeds, the commit is marked as `success`.
-1. If any of the previous jobs fails, the commit is marked as `failed` and no jobs of further stage are executed.
+1. If any of the previous jobs fails, the commit is marked as `failed` and no
+ jobs of further stage are executed.
There are also two edge cases worth mentioning:
-1. If no `stages` is defined in `.gitlab-ci.yml`, then by default the `build`, `test` and `deploy` are allowed to be used as job's stage by default.
+1. If no `stages` is defined in `.gitlab-ci.yml`, then by default the `build`,
+ `test` and `deploy` are allowed to be used as job's stage by default.
2. If a job doesn't specify `stage`, the job is assigned the `test` stage.
### types
+
Alias for [stages](#stages).
### variables
-**This feature requires `gitlab-runner` with version equal or greater than 0.5.0.**
-GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build environment.
-The variables are stored in repository and are meant to store non-sensitive project configuration, ie. RAILS_ENV or DATABASE_URL.
+_**Note:** Introduced in GitLab Runner v0.5.0._
+
+GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build
+environment. The variables are stored in the git repository and are meant to
+store non-sensitive project configuration, for example:
```yaml
variables:
@@ -109,18 +129,23 @@ variables:
These variables can be later used in all executed commands and scripts.
-The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them.
+The YAML-defined variables are also set to all created service containers,
+thus allowing to fine tune them.
### cache
-`cache` is used to specify list of files and directories which should be cached between builds.
-Caches are stored according to the branch/ref and the job name. Caches are not
-currently shared between different job names or between branches/refs. This means
-caching will benefit you if you push subsequent commits to an existing feature branch.
-**The global setting allows to specify default cached files for all jobs.**
+`cache` is used to specify a list of files and directories which should be
+cached between builds. Caches are stored according to the branch/ref and the
+job name. They are not currently shared between different job names or between
+branches/refs, which means that caching will benefit you if you push subsequent
+commits to an existing feature branch.
+
+If `cache` is defined outside the scope of the jobs, it means it is set
+globally and all jobs will use its definition.
To cache all git untracked files and files in `binaries`:
-```
+
+```yaml
cache:
untracked: true
paths:
@@ -128,9 +153,10 @@ cache:
```
## Jobs
-`.gitlab-ci.yml` allows you to specify an unlimited number of jobs.
-Each job has to have a unique `job_name`, which is not one of the keywords mentioned above.
-A job is defined by a list of parameters that define the build behaviour.
+
+`.gitlab-ci.yml` allows you to specify an unlimited number of jobs. Each job
+must have a unique name, which is not one of the Keywords mentioned above.
+A job is defined by a list of parameters that define the build behavior.
```yaml
job_name:
@@ -148,21 +174,22 @@ job_name:
allow_failure: true
```
-| keyword | required | description |
+| Keyword | Required | Description |
|---------------|----------|-------------|
-| script | required | Defines a shell script which is executed by runner |
-| stage | optional (default: test) | Defines a build stage |
-| type | optional | Alias for `stage` |
-| only | optional | Defines a list of git refs for which build is created |
-| except | optional | Defines a list of git refs for which build is not created |
-| tags | optional | Defines a list of tags which are used to select runner |
-| allow_failure | optional | Allow build to fail. Failed build doesn't contribute to commit status |
-| when | optional | Define when to run build. Can be `on_success`, `on_failure` or `always` |
-| artifacts | optional | Define list build artifacts |
-| cache | optional | Define list of files that should be cached between subsequent runs |
+| script | yes | Defines a shell script which is executed by runner |
+| stage | no (default: `test`) | Defines a build stage |
+| type | no | Alias for `stage` |
+| only | no | Defines a list of git refs for which build is created |
+| except | no | Defines a list of git refs for which build is not created |
+| tags | no | Defines a list of tags which are used to select runner |
+| allow_failure | no | Allow build to fail. Failed build doesn't contribute to commit status |
+| when | no | Define when to run build. Can be `on_success`, `on_failure` or `always` |
+| artifacts | no | Define list build artifacts |
+| cache | no | Define list of files that should be cached between subsequent runs |
### script
-`script` is a shell script which is executed by runner. The shell script is prepended with `before_script`.
+
+`script` is a shell script which is executed by the runner. For example:
```yaml
job:
@@ -170,6 +197,7 @@ job:
```
This parameter can also contain several commands using an array:
+
```yaml
job:
script:
@@ -178,31 +206,45 @@ job:
```
### stage
-`stage` allows to group build into different stages. Builds of the same `stage` are executed in `parallel`.
-For more info about the use of `stage` please check the [stages](#stages).
+
+`stage` allows to group build into different stages. Builds of the same `stage`
+are executed in `parallel`. For more info about the use of `stage` please check
+[stages](#stages).
### only and except
-This are two parameters that allow for setting a refs policy to limit when jobs are built:
-1. `only` defines the names of branches and tags for which job will be built.
-2. `except` defines the names of branches and tags for which the job wil **not** be built.
-There are a few rules that apply to usage of refs policy:
+`only` and `except` are two parameters that set a refs policy to limit when
+jobs are built:
-1. `only` and `except` are inclusive. If both `only` and `except` are defined in job specification the ref is filtered by `only` and `except`.
-1. `only` and `except` allow for using the regexp expressions.
-1. `only` and `except` allow for using special keywords: `branches` and `tags`.
-These names can be used for example to exclude all tags and all branches.
+1. `only` defines the names of branches and tags for which the job will be
+ built.
+2. `except` defines the names of branches and tags for which the job will
+ **not** be built.
+
+There are a few rules that apply to the usage of refs policy:
+
+* `only` and `except` are inclusive. If both `only` and `except` are defined
+ in a job specification, the ref is filtered by `only` and `except`.
+* `only` and `except` allow the use of regular expressions.
+* `only` and `except` allow the use of special keywords: `branches` and `tags`.
+* `only` and `except` allow to specify a repository path to filter jobs for
+ forks.
+
+In the example below, `job` will run only for refs that start with `issue-`,
+whereas all branches will be skipped.
```yaml
job:
+ # use regexp
only:
- - /^issue-.*$/ # use regexp
+ - /^issue-.*$/
+ # use special keyword
except:
- - branches # use special keyword
+ - branches
```
-1. `only` and `except` allow for specify repository path to filter jobs for forks.
-The repository path can be used to have jobs executed only for parent repository.
+The repository path can be used to have jobs executed only for the parent
+repository and not forks:
```yaml
job:
@@ -211,33 +253,47 @@ job:
except:
- master@gitlab-org/gitlab-ce
```
-The above will run `job` for all branches on `gitlab-org/gitlab-ce`, except master .
+
+The above example will run `job` for all branches on `gitlab-org/gitlab-ce`,
+except master.
### tags
-`tags` is used to select specific runners from the list of all runners that are allowed to run this project.
-During registration of a runner, you can specify the runner's tags, ie.: `ruby`, `postgres`, `development`.
-`tags` allow you to run builds with runners that have the specified tags assigned:
+`tags` is used to select specific runners from the list of all runners that are
+allowed to run this project.
-```
+During the registration of a runner, you can specify the runner's tags, for
+example `ruby`, `postgres`, `development`.
+
+`tags` allow you to run builds with runners that have the specified tags
+assigned to them:
+
+```yaml
job:
tags:
- ruby
- postgres
```
-The above specification will make sure that `job` is built by a runner that have `ruby` AND `postgres` tags defined.
+The specification above, will make sure that `job` is built by a runner that
+has both `ruby` AND `postgres` tags defined.
### when
-`when` is used to implement jobs that are run in case of failure or despite the failure.
+
+`when` is used to implement jobs that are run in case of failure or despite the
+failure.
`when` can be set to one of the following values:
-1. `on_success` - execute build only when all builds from prior stages succeeded. This is the default.
-1. `on_failure` - execute build only when at least one build from prior stages failed.
+1. `on_success` - execute build only when all builds from prior stages
+ succeeded. This is the default.
+1. `on_failure` - execute build only when at least one build from prior stages
+ failed.
1. `always` - execute build despite the status of builds from prior stages.
-```
+For example:
+
+```yaml
stages:
- build
- cleanup_build
@@ -245,28 +301,28 @@ stages:
- deploy
- cleanup
-build:
+build_job:
stage: build
script:
- make build
-cleanup_build:
+cleanup_build_job:
stage: cleanup_build
script:
- cleanup build when failed
when: on_failure
-test:
+test_job:
stage: test
script:
- make test
-deploy:
+deploy_job:
stage: deploy
script:
- make deploy
-cleanup:
+cleanup_job:
stage: cleanup
script:
- cleanup after builds
@@ -274,84 +330,108 @@ cleanup:
```
The above script will:
-1. Execute `cleanup_build` only when the `build` failed,
-2. Always execute `cleanup` as the last step in pipeline.
+
+1. Execute `cleanup_build_job` only when `build_job` fails
+2. Always execute `cleanup_job` as the last step in pipeline.
### artifacts
-`artifacts` is used to specify list of files and directories which should be attached to build after success.
-1. Send all files in `binaries` and `.config`:
+_**Note:** Introduced in GitLab Runner v0.7.0. Also, the Windows shell executor
+ does not currently support artifact uploads._
- artifacts:
- paths:
- - binaries/
- - .config
+`artifacts` is used to specify list of files and directories which should be
+attached to build after success. Below are some examples.
-2. Send all git untracked files:
+Send all files in `binaries` and `.config`:
- artifacts:
- untracked: true
+```yaml
+artifacts:
+ paths:
+ - binaries/
+ - .config
+```
-3. Send all git untracked files and files in `binaries`:
+Send all git untracked files:
- artifacts:
- untracked: true
- paths:
- - binaries/
+```yaml
+artifacts:
+ untracked: true
+```
+
+Send all git untracked files and files in `binaries`:
-The artifacts will be send after the build success to GitLab and will be accessible in GitLab interface to download.
+```yaml
+artifacts:
+ untracked: true
+ paths:
+ - binaries/
+```
-This feature requires GitLab Runner v0.7.0 or higher.
+The artifacts will be send after a successful build success to GitLab, and will
+be accessible in the GitLab UI to download.
### cache
-`cache` is used to specify list of files and directories which should be cached between builds.
-1. Cache all files in `binaries` and `.config`:
+_**Note:** Introduced in GitLab Runner v0.7.0._
- rspec:
- script: test
- cache:
- paths:
- - binaries/
- - .config
+`cache` is used to specify list of files and directories which should be cached
+between builds. Below are some examples:
-2. Cache all git untracked files:
+Cache all files in `binaries` and `.config`:
- rspec:
- script: test
- cache:
- untracked: true
-
-3. Cache all git untracked files and files in `binaries`:
+```yaml
+rspec:
+ script: test
+ cache:
+ paths:
+ - binaries/
+ - .config
+```
- rspec:
- script: test
- cache:
- untracked: true
- paths:
- - binaries/
+Cache all git untracked files:
-4. Locally defined cache overwrites globally defined options. This will cache only `binaries/`:
+```yaml
+rspec:
+ script: test
+ cache:
+ untracked: true
+```
+
+Cache all git untracked files and files in `binaries`:
+
+```yaml
+rspec:
+ script: test
+ cache:
+ untracked: true
+ paths:
+ - binaries/
+```
- cache:
- paths:
- - my/files
-
- rspec:
- script: test
- cache:
- paths:
- - binaries/
+Locally defined cache overwrites globally defined options. This will cache only
+`binaries/`:
-The cache is provided on best effort basis, so don't expect that cache will be present.
-For implementation details please check GitLab Runner.
+```yaml
+cache:
+ paths:
+ - my/files
-This feature requires GitLab Runner v0.7.0 or higher.
+rspec:
+ script: test
+ cache:
+ paths:
+ - binaries/
+```
+The cache is provided on best effort basis, so don't expect that cache will be
+always present. For implementation details please check GitLab Runner.
## Validate the .gitlab-ci.yml
+
Each instance of GitLab CI has an embedded debug tool called Lint.
-You can find the link to the Lint in the project's settings page or use short url `/lint`.
+You can find the link under `/ci/lint` of your gitlab instance.
## Skipping builds
-There is one more way to skip all builds, if your commit message contains tag [ci skip]. In this case, commit will be created but builds will be skipped
+
+If your commit message contains `[ci skip]`, the commit will be created but the
+builds will be skipped.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index f8116a8a31c..81edd8da2b8 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse
- sudo -u git -H git checkout 0.4.2
+ sudo -u git -H git checkout 0.5.1
sudo -u git -H make
### Initialize Database and Activate Advanced Features
diff --git a/doc/integration/README.md b/doc/integration/README.md
index eff39a626ae..6263353851f 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -4,10 +4,12 @@ GitLab integrates with multiple third-party services to allow external issue tra
See the documentation below for details on how to configure these services.
+- [Jira](jira.md) Integrate with the JIRA issue tracker
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP
- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth.
- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
+- [CAS](cas.md) Configure GitLab to sign in using CAS
- [Slack](slack.md) Integrate with the Slack chat service
- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
diff --git a/doc/integration/cas.md b/doc/integration/cas.md
new file mode 100644
index 00000000000..e6b2071f193
--- /dev/null
+++ b/doc/integration/cas.md
@@ -0,0 +1,62 @@
+# CAS OmniAuth Provider
+
+To enable the CAS OmniAuth provider you must register your application with your CAS instance. This requires the service URL GitLab will supply to CAS. It should be something like: `https://gitlab.example.com:443/users/auth/cas3/callback?url`. By default handling for SLO is enabled, you only need to configure CAS for backchannel logout.
+
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For installations from source:
+
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: "cas3",
+ label: "cas",
+ args: {
+ url: 'CAS_SERVER',
+ login_url: '/CAS_PATH/login',
+ service_validate_url: '/CAS_PATH/p3/serviceValidate',
+ logout_url: '/CAS_PATH/logout'} }
+ }
+ }
+ ]
+ ```
+
+ For installations from source:
+
+ ```
+ - { name: 'cas3',
+ label: 'cas',
+ args: {
+ url: 'CAS_SERVER',
+ login_url: '/CAS_PATH/login',
+ service_validate_url: '/CAS_PATH/p3/serviceValidate',
+ logout_url: '/CAS_PATH/logout'} }
+ ```
+
+1. Change 'CAS_PATH' to the root of your CAS instance (ie. `cas`).
+
+1. If your CAS instance does not use default TGC lifetimes, update the `cas3.session_duration` to at least the current TGC maximum lifetime. To explicitly disable SLO, regardless of CAS settings, set this to 0.
+
+1. Save the configuration file.
+
+1. Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a CAS tab in the sign in form.
diff --git a/doc/integration/jira.md b/doc/integration/jira.md
new file mode 100644
index 00000000000..624601d0fac
--- /dev/null
+++ b/doc/integration/jira.md
@@ -0,0 +1,113 @@
+# GitLab Jira integration
+
+GitLab can be configured to interact with Jira.
+Configuration happens via username and password.
+Connecting to a Jira server via CAS is not possible.
+
+Each project can be configured to connect to a different Jira instance, configuration is explained [here](#configuration).
+If you have one Jira instance you can pre-fill the settings page with a default template. To configure the template [see external issue tracker document](external-issue-tracker.md#service-template)).
+
+Once the project is connected to Jira, you can reference and close the issues in Jira directly from GitLab.
+
+
+## Table of Contents
+
+* [Referencing Jira Issues from GitLab](#referencing-jira-issues)
+* [Closing Jira Issues from GitLab](#closing-jira-issues)
+* [Configuration](#configuration)
+
+### Referencing Jira Issues
+
+When GitLab project has Jira issue tracker configured and enabled, mentioning Jira issue in GitLab will automatically add a comment in Jira issue with the link back to GitLab. This means that in comments in merge requests and commits referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the format:
+
+
+```
+ USER mentioned this issue in LINK_TO_THE_MENTION
+```
+
+* `USER` A user that mentioned the issue. This is the link to the user profile in GitLab.
+* `LINK_TO_THE_MENTION` Link to the origin of mention with a name of the entity where Jira issue was mentioned.
+Can be commit or merge request.
+
+
+![example of mentioning or closing the Jira issue](jira_issue_reference.png)
+
+
+### Closing Jira Issues
+
+Jira issues can be closed directly from GitLab by using trigger words, eg. `Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and merge requests.
+When a commit which contains the trigger word in the commit message is pushed, GitLab will add a comment in the mentioned Jira issue.
+
+For example, for project named PROJECT in Jira, we implemented a new feature and created a merge request in GitLab.
+
+This feature was requested in Jira issue PROJECT-7. Merge request in GitLab contains the improvement and in merge request description we say that this merge request `Closes PROJECT-7` issue.
+
+Once this merge request is merged, Jira issue will be automatically closed with a link to the commit that resolved the issue.
+
+![A Git commit that causes the Jira issue to be closed](merge_request_close_jira.png)
+
+
+![The GitLab integration user leaves a comment on Jira](jira_service_close_issue.png)
+
+
+## Configuration
+
+### Configuring JIRA
+
+We need to create a user in JIRA which will have access to all projects that need to integrate with GitLab.
+Login to your JIRA instance as admin and under Administration go to User Management and create a new user.
+As an example, we'll create a user named `gitlab` and add it to `jira-developers` group.
+
+**It is important that the user `gitlab` has write-access to projects in JIRA**
+
+### Configuring GitLab
+
+### GitLab 7.8 EE and up with JIRA v6.x
+
+To enable JIRA integration in a project, navigate to the project Settings page and go to Services. Here you will find JIRA.
+
+Fill in the required details on the page:
+
+![Jira service page](jira_service_page.png)
+
+* `description` A name for the issue tracker (to differentiate between instances, for instance).
+* `project url` The URL to the JIRA project which is being linked to this GitLab project.
+* `issues url` The URL to the JIRA project issues overview for the project that is linked to this GitLab project.
+* `new issue url` This is the URL to create a new issue in JIRA for the project linked to this GitLab project.
+* `api url` The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`.
+* `username` The username of the user created in [configuring JIRA step](#configuring-jira).
+* `password` The password of the user created in [configuring JIRA step](#configuring-jira).
+* `Jira issue transition` This is the id of a transition that moves issues to a closed state. You can find this number under [JIRA workflow administration, see screenshot](jira_workflow_screenshot.png). By default, this id is `2`. (In the example image, this is `2` as well)
+
+After saving the configuration, your GitLab project will be able to interact with the linked JIRA project.
+
+
+### GitLab 6.x-7.7 with JIRA v6.x
+
+**Note: GitLab 7.8 and up contain various integration improvements. We strongly recommend upgrading.**
+
+
+In `gitlab.yml` enable [JIRA issue tracker section by uncommenting the lines](https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115).
+This will make sure that all issues within GitLab are pointing to the JIRA issue tracker.
+
+We can also enable JIRA service that will allow us to interact with JIRA issues.
+
+For example, we can close issues in JIRA by a commit in GitLab.
+
+Go to project settings page and fill in the project name for the JIRA project:
+
+![Set the JIRA project name in GitLab to 'NEW'](jira_project_name.png)
+
+Next, go to the services page and find JIRA.
+
+![Jira services page](jira_service.png)
+
+1. Tick the active check box to enable the service.
+1. Supply the url to JIRA server, for example http://jira.sample
+1. Supply the username of a user we created under `Configuring JIRA` section, for example `gitlab`
+1. Supply the password of the user
+1. Optional: supply the JIRA api version, default is version
+1. Optional: supply the JIRA issue transition ID (issue transition to closed). This is dependant on JIRA settings, default is 2
+1. Save
+
+Now we should be able to interact with JIRA issues.
diff --git a/doc/integration/jira_issue_reference.png b/doc/integration/jira_issue_reference.png
new file mode 100644
index 00000000000..15739a22dc7
--- /dev/null
+++ b/doc/integration/jira_issue_reference.png
Binary files differ
diff --git a/doc/integration/jira_project_name.png b/doc/integration/jira_project_name.png
new file mode 100644
index 00000000000..5986fdb63fb
--- /dev/null
+++ b/doc/integration/jira_project_name.png
Binary files differ
diff --git a/doc/integration/jira_service.png b/doc/integration/jira_service.png
new file mode 100644
index 00000000000..1f6628c4371
--- /dev/null
+++ b/doc/integration/jira_service.png
Binary files differ
diff --git a/doc/integration/jira_service_close_issue.png b/doc/integration/jira_service_close_issue.png
new file mode 100644
index 00000000000..67dfc6144c4
--- /dev/null
+++ b/doc/integration/jira_service_close_issue.png
Binary files differ
diff --git a/doc/integration/jira_service_page.png b/doc/integration/jira_service_page.png
new file mode 100644
index 00000000000..69ec44e826f
--- /dev/null
+++ b/doc/integration/jira_service_page.png
Binary files differ
diff --git a/doc/integration/jira_workflow_screenshot.png b/doc/integration/jira_workflow_screenshot.png
new file mode 100644
index 00000000000..8635a32eb68
--- /dev/null
+++ b/doc/integration/jira_workflow_screenshot.png
Binary files differ
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index a8dc5c24df2..cc8a22cd003 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -1,10 +1,11 @@
# Rake tasks
- [Backup restore](backup_restore.md)
+- [Check](check.md)
- [Cleanup](cleanup.md)
- [Features](features.md)
- [Maintenance](maintenance.md) and self-checks
- [User management](user_management.md)
- [Web hooks](web_hooks.md)
- [Import](import.md) of git repositories in bulk
-- [Rebuild authorized_keys file](http://doc.gitlab.com/ce/raketasks/maintenance.html#rebuild-authorized_keys-file) task for administrators \ No newline at end of file
+- [Rebuild authorized_keys file](http://doc.gitlab.com/ce/raketasks/maintenance.html#rebuild-authorized_keys-file) task for administrators
diff --git a/doc/raketasks/check.md b/doc/raketasks/check.md
new file mode 100644
index 00000000000..3ff3fee6a40
--- /dev/null
+++ b/doc/raketasks/check.md
@@ -0,0 +1,63 @@
+# Check Rake Tasks
+
+## Repository Integrity
+
+Even though Git is very resilient and tries to prevent data integrity issues,
+there are times when things go wrong. The following Rake tasks intend to
+help GitLab administrators diagnose problem repositories so they can be fixed.
+
+There are 3 things that are checked to determine integrity.
+
+1. Git repository file system check ([git fsck](https://git-scm.com/docs/git-fsck)).
+ This step verifies the connectivity and validity of objects in the repository.
+1. Check for `config.lock` in the repository directory.
+1. Check for any branch/references lock files in `refs/heads`.
+
+It's important to note that the existence of `config.lock` or reference locks
+alone do not necessarily indicate a problem. Lock files are routinely created
+and removed as Git and GitLab perform operations on the repository. They serve
+to prevent data integrity issues. However, if a Git operation is interrupted these
+locks may not be cleaned up properly.
+
+The following symptoms may indicate a problem with repository integrity. If users
+experience these symptoms you may use the rake tasks described below to determine
+exactly which repositories are causing the trouble.
+
+- Receiving an error when trying to push code - `remote: error: cannot lock ref`
+- A 500 error when viewing the GitLab dashboard or when accessing a specific project.
+
+### Check all GitLab repositories
+
+This task loops through all repositories on the GitLab server and runs the
+3 integrity checks described previously.
+
+```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:repo:check
+
+# installation from source
+bundle exec rake gitlab:repo:check RAILS_ENV=production
+```
+
+### Check repositories for a specific user
+
+This task checks all repositories that a specific user has access to. This is important
+because sometimes you know which user is experiencing trouble but you don't know
+which project might be the cause.
+
+If the rake task is executed without brackets at the end, you will be prompted
+to enter a username.
+
+```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:user:check_repos
+sudo gitlab-rake gitlab:user:check_repos[<username>]
+
+# installation from source
+bundle exec rake gitlab:user:check_repos RAILS_ENV=production
+bundle exec rake gitlab:user:check_repos[<username>] RAILS_ENV=production
+```
+
+Example output:
+
+![gitlab:user:check_repos output](check_repos_output.png)
diff --git a/doc/raketasks/check_repos_output.png b/doc/raketasks/check_repos_output.png
new file mode 100644
index 00000000000..916b1685101
--- /dev/null
+++ b/doc/raketasks/check_repos_output.png
Binary files differ
diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md
index e69c4f7ed3c..c4661dc16af 100644
--- a/doc/update/8.2-to-8.3.md
+++ b/doc/update/8.2-to-8.3.md
@@ -67,7 +67,7 @@ sudo -u git -H git checkout 8-3-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch --all
-sudo -u git -H git checkout v2.6.8
+sudo -u git -H git checkout v2.6.9
```
### 5. Update gitlab-workhorse
@@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1.
```bash
cd /home/git/gitlab-workhorse
sudo -u git -H git fetch --all
-sudo -u git -H git checkout 0.4.2
+sudo -u git -H git checkout 0.5.1
sudo -u git -H make
```
@@ -115,6 +115,12 @@ git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gi
#### Nginx configuration
+GitLab 8.3 introduces major changes in the NGINX configuration.
+Because all HTTP requests pass through gitlab-workhorse now a lot of
+directives need to be removed from NGINX. During future upgrades there
+should be much less changes in the NGINX configuration because of
+this.
+
View changes between the previous recommended Nginx configuration and the
current one:
@@ -134,6 +140,18 @@ via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-3-stable/lib/support/init.d/gitlab.default.example#L34
+#### Init script
+
+We updated the init script for GitLab in order to pass new
+configuration options to gitlab-workhorse. We let gitlab-workhorse
+connect to the Rails application via a Unix domain socket and we tell
+it where the 'public' directory of GitLab is.
+
+```
+cd /home/git/gitlab
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
### 8. Use Redis v2.8.0+
Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index d2642495c9a..3651b55f438 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -19,3 +19,4 @@
- ["Work In Progress" Merge Requests](wip_merge_requests.md)
- [Merge When Build Succeeds](merge_when_build_succeeds.md)
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
+- [Importing from SVN, GitHub, BitBucket, etc](importing/README.md)
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
index 7ccf06fbd60..18e5d950866 100644
--- a/doc/workflow/importing/README.md
+++ b/doc/workflow/importing/README.md
@@ -1,13 +1,17 @@
# Migrating projects to a GitLab instance
1. [Bitbucket](import_projects_from_bitbucket.md)
-2. [GitHub](import_projects_from_github.md)
-3. [GitLab.com](import_projects_from_gitlab_com.md)
-4. [FogBugz](import_projects_from_fogbugz.md)
-4. [SVN](migrating_from_svn.md)
+1. [GitHub](import_projects_from_github.md)
+1. [GitLab.com](import_projects_from_gitlab_com.md)
+1. [FogBugz](import_projects_from_fogbugz.md)
+1. [SVN](migrating_from_svn.md)
-### Note
-* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported.
+In addition to the specific migration documentation above, you can import any
+Git repository via HTTP from the New Project page. Be aware that if the
+repository is too large the import can timeout.
+
+### Migrating from self-hosted GitLab to GitLab.com
+
+You can copy your repos by changing the remote and pushing to the new server;
+but issues and merge requests can't be imported.
-* You can import any Git repository via HTTP from the New Project page.
-If the repository is too large, it can timeout.
diff --git a/doc/workflow/importing/migrating_from_svn.md b/doc/workflow/importing/migrating_from_svn.md
index 1938ccd0c26..b355a91b5a6 100644
--- a/doc/workflow/importing/migrating_from_svn.md
+++ b/doc/workflow/importing/migrating_from_svn.md
@@ -1,17 +1,78 @@
# Migrating from SVN to GitLab
-SVN stands for Subversion and is a version control system (VCS).
-Git is a distributed version control system.
+Subversion (SVN) is a central version control system (VCS) while
+Git is a distributed version control system. There are some major differences
+between the two, for more information consult your favorite search engine.
-There are some major differences between the two, for more information consult your favorite search engine.
+If you are currently using an SVN repository, you can migrate the repository
+to Git and GitLab. We recommend a hard cut over - run the migration command once
+and then have all developers start using the new GitLab repository immediately.
+Otherwise, it's hard to keep changing in sync in both directions. The conversion
+process should be run on a local workstation.
-Git has tools for migrating SVN repositories to git, namely `git svn`. You can read more about this at
-[git documentation pages](https://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion).
+Install `svn2git`. On all systems you can install as a Ruby gem if you already
+have Ruby and Git installed.
-Apart from the [official git documentation](https://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git) there is also
-user created step by step guide for migrating from SVN to GitLab.
+```bash
+sudo gem install svn2git
+```
-[Benjamin New](https://github.com/leftclickben) wrote [a guide that shows how to do a migration](https://gist.github.com/leftclickben/322b7a3042cbe97ed2af). Mirrors can be found [here](https://gitlab.com/snippets/2168) and [here](https://gist.github.com/maxlazio/f1b593b0d00aa966e9ca).
+On Debian-based Linux distributions you can install the native packages:
+
+```bash
+sudo apt-get install git-core git-svn ruby
+```
+
+Optionally, prepare an authors file so `svn2git` can map SVN authors to Git authors.
+If you choose not to create the authors file then commits will not be attributed
+to the correct GitLab user. Some users may not consider this a big issue while
+others will want to ensure they complete this step. If you choose to map authors
+you will be required to map every author that is present on changes in the SVN
+repository. If you don't, the conversion will fail and you will have to update
+the author file accordingly. The following command will search through the
+repository and output a list of authors.
+
+```bash
+svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq
+```
+
+Use the output from the last command to construct the authors file.
+Create a file called `authors.txt` and add one mapping per line.
+
+```
+janedoe = Jane Doe <janedoe@example.com>
+johndoe = John Doe <johndoe@example.com>
+```
+
+If your SVN repository is in the standard format (trunk, branches, tags,
+not nested) the conversion is simple. For a non-standard repository see
+[svn2git documentation](https://github.com/nirvdrum/svn2git). The following
+command will checkout the repository and do the conversion in the current
+working directory. Be sure to create a new directory for each repository before
+running the `svn2git` command. The conversion process will take some time.
+
+```bash
+svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
+```
+
+If your SVN repository requires a username and password add the
+`--username <username>` and `--password <password` flags to the above command.
+`svn2git` also supports excluding certain file paths, branches, tags, etc. See
+[svn2git documentation](https://github.com/nirvdrum/svn2git) or run
+`svn2git --help` for full documentation on all of the available options.
+
+Create a new GitLab project, where you will eventually push your converted code.
+Copy the SSH or HTTP(S) repository URL from the project page. Add the GitLab
+repository as a Git remote and push all the changes. This will push all commits,
+branches and tags.
+
+```bash
+git remote add origin git@gitlab.com:<group>/<project>.git
+git push --all origin
+```
## Contribute to this guide
-We welcome all contributions that would expand this guide with instructions on how to migrate from SVN and other version control systems.
+We welcome all contributions that would expand this guide with instructions on
+how to migrate from SVN and other version control systems.
+
+
diff --git a/features/project/issues/award_emoji.feature b/features/project/issues/award_emoji.feature
index cbf2e7104ab..9a06fdc2ee6 100644
--- a/features/project/issues/award_emoji.feature
+++ b/features/project/issues/award_emoji.feature
@@ -19,6 +19,12 @@ Feature: Award Emoji
Then I can see the activity and food categories
@javascript
+ Scenario: I can search emoji
+ Given I click to emoji-picker
+ And I search "hand"
+ Then I see search result for "hand"
+
+ @javascript
Scenario: I add award emoji using regular comment
- Given I leave comment with a single emoji
- Then I have award added
+ Given I leave comment with a single emoji
+ Then I have award added
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index f08b30e0b88..ab234bc7507 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -197,3 +197,9 @@ Feature: Project Issues
And I should not see labels field
And I submit new issue "500 error on profile"
Then I should see issue "500 error on profile"
+
+ @javascript
+ Scenario: Another user adds a comment to issue I'm currently viewing
+ Given I visit issue page "Release 0.4"
+ And another user adds a comment with text "Yay!" to issue "Release 0.4"
+ Then I should see a new comment with text "Yay!"
diff --git a/features/project/service.feature b/features/project/service.feature
index ff3e7a0b38e..3a7b8308524 100644
--- a/features/project/service.feature
+++ b/features/project/service.feature
@@ -55,6 +55,12 @@ Feature: Project Services
And I fill email on push settings
Then I should see email on push service settings saved
+ Scenario: Activate JIRA service
+ When I visit project "Shop" services page
+ And I click jira service link
+ And I fill jira settings
+ Then I should see jira service settings saved
+
Scenario: Activate Irker (IRC Gateway) service
When I visit project "Shop" services page
And I click Irker service link
diff --git a/features/steps/explore/groups.rb b/features/steps/explore/groups.rb
index 87cd33c37eb..87f32e70d59 100644
--- a/features/steps/explore/groups.rb
+++ b/features/steps/explore/groups.rb
@@ -75,18 +75,18 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
name: projectname,
path: "#{groupname}-#{projectname}",
visibility_level: visibility_level
- )
+ )
create(:issue,
title: "#{projectname} feature",
project: project
- )
+ )
create(:merge_request,
title: "#{projectname} feature implemented",
source_project: project,
target_project: project
- )
+ )
create(:closed_issue_event,
project: project
- )
+ )
end
end
diff --git a/features/steps/explore/projects.rb b/features/steps/explore/projects.rb
index f819dec2192..742ba5d71f6 100644
--- a/features/steps/explore/projects.rb
+++ b/features/steps/explore/projects.rb
@@ -61,11 +61,11 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
create(:issue,
title: "Bug",
project: public_project
- )
+ )
create(:issue,
title: "New feature",
project: public_project
- )
+ )
visit namespace_project_issues_path(public_project.namespace, public_project)
end
@@ -80,11 +80,11 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
create(:issue,
title: "Internal Bug",
project: internal_project
- )
+ )
create(:issue,
title: "New internal feature",
project: internal_project
- )
+ )
visit namespace_project_issues_path(internal_project.namespace, internal_project)
end
@@ -104,7 +104,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
title: "Bug fix for public project",
source_project: public_project,
target_project: public_project,
- )
+ )
end
step 'I should see list of merge requests for "Community" project' do
@@ -121,7 +121,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
title: "Feature implemented",
source_project: internal_project,
target_project: internal_project
- )
+ )
end
step 'I should see list of merge requests for "Internal" project' do
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index f5e3fee61c0..4c5122d1b7d 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -85,7 +85,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
step 'I should see new group "Owned" avatar' do
expect(owned_group.avatar).to be_instance_of AvatarUploader
- expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/banana_sample.gif"
+ expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name:"Owned").id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 40b2aa7c357..0305f7e6da0 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -34,7 +34,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I should see new avatar' do
expect(@user.avatar).to be_instance_of AvatarUploader
- expect(@user.avatar.url).to eq "/uploads/user/avatar/#{ @user.id }/banana_sample.gif"
+ expect(@user.avatar.url).to eq "/uploads/user/avatar/#{@user.id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index d3675060994..cbdce78dc0c 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -41,7 +41,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
click_button "Compare branches and continue"
- expect(page).to have_content "New Merge Request"
+ expect(page).to have_css("h3.page-title", text: "New Merge Request")
+
fill_in "merge_request_title", with: "Merge Request On Forked Project"
end
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index c94d0ba7306..a7e15398819 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -52,4 +52,16 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
click_button 'Add Comment'
end
end
+
+ step 'I search "hand"' do
+ page.within('.emoji-menu-content') do
+ fill_in 'emoji_search', with: 'hand'
+ end
+ end
+
+ step 'I see search result for "hand"' do
+ page.within '.emoji-menu-content' do
+ expect(page).to have_selector '[data-emoji="raised_hand"]'
+ end
+ end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index a13044c3ae1..4a7ff21d385 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -284,6 +284,16 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
end
+ step 'another user adds a comment with text "Yay!" to issue "Release 0.4"' do
+ issue = Issue.find_by!(title: 'Release 0.4')
+ create(:note_on_issue, noteable: issue, note: 'Yay!')
+ end
+
+ step 'I should see a new comment with text "Yay!"' do
+ page.within '#notes' do
+ expect(page).to have_content('Yay!')
+ end
+ end
def filter_issue(text)
fill_in 'issue_search', with: text
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 0d340d97ff9..be993d11093 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -273,7 +273,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see merged request' do
- page.within '.issue-box' do
+ page.within '.status-box' do
expect(page).to have_content "Merged"
end
end
@@ -283,7 +283,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see reopened merge request "Bug NS-04"' do
- page.within '.issue-box' do
+ page.within '.status-box' do
expect(page).to have_content "Open"
end
end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 9ca7c8ebbc7..37bf52b4a95 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -37,7 +37,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should see new project avatar' do
expect(@project.avatar).to be_instance_of AvatarUploader
url = @project.avatar.url
- expect(url).to eq "/uploads/project/avatar/#{ @project.id }/banana_sample.gif"
+ expect(url).to eq "/uploads/project/avatar/#{@project.id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb
index ed3957ca873..536199ddb4f 100644
--- a/features/steps/project/services.rb
+++ b/features/steps/project/services.rb
@@ -173,6 +173,24 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
expect(find_field('Sound').find('option[selected]').value).to eq 'bike'
end
+ step 'I click jira service link' do
+ click_link 'JIRA'
+ end
+
+ step 'I fill jira settings' do
+ fill_in 'Project url', with: 'http://jira.example'
+ fill_in 'Username', with: 'gitlab'
+ fill_in 'Password', with: 'gitlab'
+ fill_in 'Api url', with: 'http://jira.example/rest/api/2'
+ click_button 'Save'
+ end
+
+ step 'I should see jira service settings saved' do
+ expect(find_field('Project url').value).to eq 'http://jira.example'
+ expect(find_field('Username').value).to eq 'gitlab'
+ expect(find_field('Api url').value).to eq 'http://jira.example/rest/api/2'
+ end
+
step 'I click Atlassian Bamboo CI service link' do
click_link 'Atlassian Bamboo CI'
end
diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb
index a3aef9bf8c3..504654f90dd 100644
--- a/features/steps/project/snippets.rb
+++ b/features/steps/project/snippets.rb
@@ -42,7 +42,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
end
step 'I click link "Edit"' do
- page.within ".page-title" do
+ page.within ".detail-page-header" do
click_link "Edit"
end
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index b88709620ab..0c6df18ce2e 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -238,13 +238,13 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I am redirected to the new file' do
- expect(current_path).to eq(namespace_project_blob_path(
- @project.namespace, @project, 'master/' + new_file_name))
+ expect(current_path).to eq(
+ namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name))
end
step 'I am redirected to the new file with directory' do
- expect(current_path).to eq(namespace_project_blob_path(
- @project.namespace, @project, 'master/' + new_file_name_with_directory))
+ expect(current_path).to eq(
+ namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name_with_directory))
end
step 'I am redirected to the new merge request page' do
@@ -252,8 +252,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I am redirected to the root directory' do
- expect(current_path).to eq(namespace_project_tree_path(
- @project.namespace, @project, 'master/'))
+ expect(current_path).to eq(
+ namespace_project_tree_path(@project.namespace, @project, 'master/'))
end
step "I don't see the permalink link" do
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index dd466cde28d..c6a0ae2ba38 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -166,7 +166,7 @@ module SharedDiffNote
end
step 'I should see add a diff comment button' do
- expect(page).to have_css('.js-add-diff-note-button', visible: true)
+ expect(page).to have_css('.js-add-diff-note-button')
end
step 'I should see an empty diff comment form' do
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index c74a5fd3bc7..b33bd332655 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -212,8 +212,8 @@ module SharedPaths
end
step 'I visit a binary file in the repo' do
- visit namespace_project_blob_path(@project.namespace, @project, File.join(
- root_ref, 'files/images/logo-black.png'))
+ visit namespace_project_blob_path(@project.namespace, @project,
+ File.join(root_ref, 'files/images/logo-black.png'))
end
step "I visit my project's commits page" do
@@ -316,8 +316,8 @@ module SharedPaths
end
step 'I am on the ".gitignore" edit file page' do
- expect(current_path).to eq(namespace_project_edit_blob_path(
- @project.namespace, @project, File.join(root_ref, '.gitignore')))
+ expect(current_path).to eq(
+ namespace_project_edit_blob_path(@project.namespace, @project, File.join(root_ref, '.gitignore')))
end
step 'I visit project source page for "6d39438"' do
diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb
index 80d1ddeef05..023032e679f 100644
--- a/features/steps/snippets/snippets.rb
+++ b/features/steps/snippets/snippets.rb
@@ -13,7 +13,7 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
end
step 'I click link "Edit"' do
- page.within ".page-title" do
+ page.within ".detail-page-header" do
click_link "Edit"
end
end
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
index 31dbf0feb2f..4156c7ec484 100644
--- a/features/support/capybara.rb
+++ b/features/support/capybara.rb
@@ -2,7 +2,7 @@ require 'spinach/capybara'
require 'capybara/poltergeist'
# Give CI some extra time
-timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 10
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 15
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
diff --git a/fixtures/emojis/aliases.json b/fixtures/emojis/aliases.json
new file mode 100644
index 00000000000..547ce7978b3
--- /dev/null
+++ b/fixtures/emojis/aliases.json
@@ -0,0 +1,367 @@
+{
+ "northeast_pointing_airplane":"airplane_northeast",
+ "small_airplane":"airplane_small",
+ "up_pointing_small_airplane":"airplane_small_up",
+ "up_pointing_airplane":"airplane_up",
+ "left_anger_bubble":"anger_left",
+ "right_anger_bubble":"anger_right",
+ "ballot_box_with_ballot":"ballot_box",
+ "ballot_box_with_bold_check":"ballot_box_check",
+ "ballot_box_with_script_x":"ballot_box_x",
+ "ballot_script_x":"ballot_x",
+ "beach_with_umbrella":"beach",
+ "bellhop_bell":"bellhop",
+ "bouquet_of_flowers":"bouquet2",
+ "bullhorn_with_sound_waves":"bullhorn_waves",
+ "pocket calculator":"calculator",
+ "spiral_calendar_pad":"calendar_spiral",
+ "card_file_box":"card_box",
+ "tape_cartridge":"cartridge",
+ "city_sunrise":"city_sunset",
+ "mantlepiece_clock":"clock",
+ "clockwise_right_and_left_semicircle_arrows":"clockwise_arrows",
+ "cloud_with_lightning":"cloud_lightning",
+ "cloud_with_rain":"cloud_rain",
+ "cloud_with_snow":"cloud_snow",
+ "cloud_with_tornado":"cloud_tornado",
+ "old_personal_computer":"computer_old",
+ "building_construction":"contruction_site",
+ "couch_and_lamp":"couch",
+ "couple_with_heart_mm":"couple_mm",
+ "couple_with_heart_ww":"couple_ww",
+ "lower_left_crayon":"crayon",
+ "heavy_latin_cross":"cross_heavy",
+ "white_latin_cross":"cross_white",
+ "black_skull_and_crossbones":"crossbones",
+ "passenger_ship":"cruise_ship",
+ "dagger_knife":"dagger",
+ "desktop_computer":"desktop",
+ "card_index_dividers":"dividers",
+ "document_with_text":"document_text",
+ "dove_of_peace":"dove",
+ "email":"e-mail",
+ "back_of_envelope":"envelope_back",
+ "flying_envelope":"envelope_flying",
+ "stamped_envelope":"envelope_stamped",
+ "pen_over_stamped_envelope":"envelope_stamped_pen",
+ "white_down_pointing_left_hand_index":"finger_pointing_down",
+ "sideways_white_down_pointing_index":"finger_pointing_down2",
+ "sideways_white_left_pointing_index":"finger_pointing_left",
+ "sideways_white_right_pointing_index":"finger_pointing_right",
+ "sideways_white_up_pointing_index":"finger_pointing_up",
+ "flame":"fire",
+ "oncoming_fire_engine":"fire_engine_oncoming",
+ "ac":"flag_ac",
+ "ad":"flag_ad",
+ "ae":"flag_ae",
+ "af":"flag_af",
+ "ag":"flag_ag",
+ "ai":"flag_ai",
+ "al":"flag_al",
+ "am":"flag_am",
+ "ao":"flag_ao",
+ "ar":"flag_ar",
+ "at":"flag_at",
+ "au":"flag_au",
+ "aw":"flag_aw",
+ "az":"flag_az",
+ "ba":"flag_ba",
+ "bb":"flag_bb",
+ "bd":"flag_bd",
+ "be":"flag_be",
+ "bf":"flag_bf",
+ "bg":"flag_bg",
+ "bh":"flag_bh",
+ "bi":"flag_bi",
+ "bj":"flag_bj",
+ "waving_black_flag":"flag_black",
+ "bm":"flag_bm",
+ "bn":"flag_bn",
+ "bo":"flag_bo",
+ "br":"flag_br",
+ "bs":"flag_bs",
+ "bt":"flag_bt",
+ "bw":"flag_bw",
+ "by":"flag_by",
+ "bz":"flag_bz",
+ "ca":"flag_ca",
+ "congo":"flag_cd",
+ "cf":"flag_cf",
+ "cg":"flag_cg",
+ "ch":"flag_ch",
+ "ci":"flag_ci",
+ "chile":"flag_cl",
+ "cm":"flag_cm",
+ "cn":"flag_cn",
+ "co":"flag_co",
+ "cr":"flag_cr",
+ "cu":"flag_cu",
+ "cv":"flag_cv",
+ "cy":"flag_cy",
+ "cz":"flag_cz",
+ "de":"flag_de",
+ "dj":"flag_dj",
+ "dk":"flag_dk",
+ "dm":"flag_dm",
+ "do":"flag_do",
+ "dz":"flag_dz",
+ "ec":"flag_ec",
+ "ee":"flag_ee",
+ "eg":"flag_eg",
+ "eh":"flag_eh",
+ "er":"flag_er",
+ "es":"flag_es",
+ "et":"flag_et",
+ "fi":"flag_fi",
+ "fj":"flag_fj",
+ "fk":"flag_fk",
+ "fm":"flag_fm",
+ "fo":"flag_fo",
+ "fr":"flag_fr",
+ "ga":"flag_ga",
+ "gb":"flag_gb",
+ "gd":"flag_gd",
+ "ge":"flag_ge",
+ "gh":"flag_gh",
+ "gi":"flag_gi",
+ "gl":"flag_gl",
+ "gm":"flag_gm",
+ "gn":"flag_gn",
+ "gq":"flag_gq",
+ "gr":"flag_gr",
+ "gt":"flag_gt",
+ "gu":"flag_gu",
+ "gw":"flag_gw",
+ "gy":"flag_gy",
+ "hk":"flag_hk",
+ "hn":"flag_hn",
+ "hr":"flag_hr",
+ "ht":"flag_ht",
+ "hu":"flag_hu",
+ "indonesia":"flag_id",
+ "ie":"flag_ie",
+ "il":"flag_il",
+ "in":"flag_in",
+ "iq":"flag_iq",
+ "ir":"flag_ir",
+ "is":"flag_is",
+ "it":"flag_it",
+ "je":"flag_je",
+ "jm":"flag_jm",
+ "jo":"flag_jo",
+ "jp":"flag_jp",
+ "ke":"flag_ke",
+ "kg":"flag_kg",
+ "kh":"flag_kh",
+ "ki":"flag_ki",
+ "km":"flag_km",
+ "kn":"flag_kn",
+ "kp":"flag_kp",
+ "kr":"flag_kr",
+ "kw":"flag_kw",
+ "ky":"flag_ky",
+ "kz":"flag_kz",
+ "la":"flag_la",
+ "lb":"flag_lb",
+ "lc":"flag_lc",
+ "li":"flag_li",
+ "lk":"flag_lk",
+ "lr":"flag_lr",
+ "ls":"flag_ls",
+ "lt":"flag_lt",
+ "lu":"flag_lu",
+ "lv":"flag_lv",
+ "ly":"flag_ly",
+ "ma":"flag_ma",
+ "mc":"flag_mc",
+ "md":"flag_md",
+ "me":"flag_me",
+ "mg":"flag_mg",
+ "mh":"flag_mh",
+ "mk":"flag_mk",
+ "ml":"flag_ml",
+ "mm":"flag_mm",
+ "mn":"flag_mn",
+ "mo":"flag_mo",
+ "mr":"flag_mr",
+ "ms":"flag_ms",
+ "mt":"flag_mt",
+ "mu":"flag_mu",
+ "mv":"flag_mv",
+ "mw":"flag_mw",
+ "mx":"flag_mx",
+ "my":"flag_my",
+ "mz":"flag_mz",
+ "na":"flag_na",
+ "nc":"flag_nc",
+ "ne":"flag_ne",
+ "nigeria":"flag_ng",
+ "ni":"flag_ni",
+ "nl":"flag_nl",
+ "no":"flag_no",
+ "np":"flag_np",
+ "nr":"flag_nr",
+ "nu":"flag_nu",
+ "nz":"flag_nz",
+ "om":"flag_om",
+ "pa":"flag_pa",
+ "pe":"flag_pe",
+ "pf":"flag_pf",
+ "pg":"flag_pg",
+ "ph":"flag_ph",
+ "pk":"flag_pk",
+ "pl":"flag_pl",
+ "pr":"flag_pr",
+ "ps":"flag_ps",
+ "pt":"flag_pt",
+ "pw":"flag_pw",
+ "py":"flag_py",
+ "qa":"flag_qa",
+ "ro":"flag_ro",
+ "rs":"flag_rs",
+ "ru":"flag_ru",
+ "rw":"flag_rw",
+ "saudiarabia":"flag_sa",
+ "saudi":"flag_sa",
+ "sb":"flag_sb",
+ "sc":"flag_sc",
+ "sd":"flag_sd",
+ "se":"flag_se",
+ "sg":"flag_sg",
+ "sh":"flag_sh",
+ "si":"flag_si",
+ "sk":"flag_sk",
+ "sl":"flag_sl",
+ "sm":"flag_sm",
+ "sn":"flag_sn",
+ "so":"flag_so",
+ "sr":"flag_sr",
+ "st":"flag_st",
+ "sv":"flag_sv",
+ "sy":"flag_sy",
+ "sz":"flag_sz",
+ "td":"flag_td",
+ "tg":"flag_tg",
+ "th":"flag_th",
+ "tj":"flag_tj",
+ "tl":"flag_tl",
+ "turkmenistan":"flag_tm",
+ "tn":"flag_tn",
+ "to":"flag_to",
+ "tr":"flag_tr",
+ "tt":"flag_tt",
+ "tuvalu":"flag_tv",
+ "tw":"flag_tw",
+ "tz":"flag_tz",
+ "ua":"flag_ua",
+ "ug":"flag_ug",
+ "us":"flag_us",
+ "uy":"flag_uy",
+ "uz":"flag_uz",
+ "va":"flag_va",
+ "vc":"flag_vc",
+ "ve":"flag_ve",
+ "vi":"flag_vi",
+ "vn":"flag_vn",
+ "vu":"flag_vu",
+ "wf":"flag_wf",
+ "waving_white_flag":"flag_white",
+ "ws":"flag_ws",
+ "xk":"flag_xk",
+ "ye":"flag_ye",
+ "za":"flag_za",
+ "zm":"flag_zm",
+ "zw":"flag_zw",
+ "clamshell_mobile_phone":"flip_phone",
+ "black_hard_shell_floppy_disk":"floppy_black",
+ "white_hard_shell_floppy_disk":"floppy_white",
+ "open_folder":"folder_open",
+ "fork_and_knife_with_plate":"fork_knife_plate",
+ "frame_with_picture":"frame_photo",
+ "frame_with_tiles":"frame_tiles",
+ "frame_with_an_x":"frame_x",
+ "anguished":"frowning",
+ "raised_hand_with_fingers_splayed":"hand_splayed",
+ "reversed_raised_hand_with_fingers_splayed":"hand_splayed_reverse",
+ "reversed_victory_hand":"hand_victory",
+ "heart_with_tip_on_the_left":"heart_tip",
+ "house_buildings":"homes",
+ "derelict_house_building":"house_abandoned",
+ "circled_information_source":"info",
+ "desert_island":"island",
+ "up_pointing_military_airplane":"jet_up",
+ "old_key":"key2",
+ "wired_keyboard":"keyboard",
+ "keyboard_and_mouse":"keyboard_mouse",
+ "musical_keyboard_with_jacks":"keyboard_with_jacks",
+ "couplekiss_mm":"kiss_mm",
+ "couplekiss_ww":"kiss_ww",
+ "satisfied":"laughing",
+ "left_hand_telephone_receiver":"left_receiver",
+ "man_in_business_suit_levitating":"levitate",
+ "weight_lifter":"lifter",
+ "light_mark":"light_check_mark",
+ "world_map":"map",
+ "sports_medal":"medal",
+ "studio_microphone":"microphone2",
+ "reversed_hand_with_middle_finger_extended":"middle_finger",
+ "lightning_mood_bubble":"mood_bubble_lightning",
+ "lightning_mood":"mood_lightning",
+ "racing_motorcycle":"motorcycle",
+ "snow_capped_mountain":"mountain_snow",
+ "one_button_mouse":"mouse_one",
+ "three_networked_computers":"network",
+ "rolled_up_newspaper":"newspaper2",
+ "note_page":"note",
+ "empty_note_page":"note_empty",
+ "note_pad":"notepad",
+ "empty_note_pad":"notepad_empty",
+ "spiral_note_pad":"notepad_spiral",
+ "oil_drum":"oil",
+ "grandma":"older_woman",
+ "optical_disc_icon":"optical_disk",
+ "lower_left_paintbrush":"paintbrush",
+ "linked_paperclips":"paperclips",
+ "national_park":"park",
+ "lower_left_ballpoint_pen":"pen_ballpoint",
+ "lower_left_fountain_pen":"pen_fountain",
+ "memo":"pencil",
+ "lower_left_pencil":"pencil3",
+ "black_pennant":"pennant_black",
+ "white_pennant":"pennant_white",
+ "no_piracy":"piracy",
+ "shit":"poop",
+ "hankey":"poop",
+ "poo":"poop",
+ "prohibited_sign":"prohibited",
+ "film_projector":"projector",
+ "racing_car":"race_car",
+ "railroad_track":"railway_track",
+ "right_speaker_with_one_sound_wave":"right_speaker_one",
+ "right_speaker_with_three_sound_waves":"right_speaker_three",
+ "skeleton":"skull",
+ "slightly_frowning_face":"slight_frown",
+ "slightly_smiling_face":"slight_smile",
+ "speaking_head_in_silhouette":"speaking_head",
+ "left_speech_bubble":"speech_left",
+ "right_speech_bubble":"speech_right",
+ "three_speech_bubbles":"speech_three",
+ "two_speech_bubbles":"speech_two",
+ "sleuth_or_spy":"spy",
+ "portable_stereo":"stereo",
+ "black_touchtone_telephone":"telephone_black",
+ "white_touchtone_telephone":"telephone_white",
+ "left_thought_bubble":"thought_left",
+ "right_thought_bubble":"thought_right",
+ "reversed_thumbs_down_sign":"thumbs_down_reverse",
+ "reversed_thumbs_up_sign":"thumbs_up_reverse",
+ "-1":"thumbsdown",
+ "+1":"thumbsup",
+ "admission_tickets":"tickets",
+ "hammer_and_wrench":"tools",
+ "diesel_locomotive":"train_diesel",
+ "triangle_with_rounded_corners":"triangle_round",
+ "turned_ok_hand_sign":"turned_ok_hand",
+ "raised_hand_with_part_between_middle_and_ring_fingers":"vulcan",
+ "left_writing_hand":"writing_hand"
+} \ No newline at end of file
diff --git a/fixtures/emojis/index.json b/fixtures/emojis/index.json
new file mode 100644
index 00000000000..60ef2399e14
--- /dev/null
+++ b/fixtures/emojis/index.json
@@ -0,0 +1,13376 @@
+{
+ "100": {
+ "unicode": "1F4AF",
+ "unicode_alternates": [],
+ "name": "hundred points symbol",
+ "shortname": ":100:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["numbers", "perfect", "score", "100", "percent", "a", "plus", "perfect", "school", "quiz", "score", "test", "exam"],
+ "moji": "💯"
+ },
+ "1234": {
+ "unicode": "1F522",
+ "unicode_alternates": [],
+ "name": "input symbol for numbers",
+ "shortname": ":1234:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "numbers"],
+ "moji": "🔢"
+ },
+ "8ball": {
+ "unicode": "1F3B1",
+ "unicode_alternates": [],
+ "name": "billiards",
+ "shortname": ":8ball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["pool", "billiards", "eight ball", "pool", "pocket ball", "cue"],
+ "moji": "🎱"
+ },
+ "a": {
+ "unicode": "1F170",
+ "unicode_alternates": [],
+ "name": "negative squared latin capital letter a",
+ "shortname": ":a:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "letter", "red-square"],
+ "moji": "🅰"
+ },
+ "ab": {
+ "unicode": "1F18E",
+ "unicode_alternates": [],
+ "name": "negative squared ab",
+ "shortname": ":ab:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "red-square"],
+ "moji": "🆎"
+ },
+ "abc": {
+ "unicode": "1F524",
+ "unicode_alternates": [],
+ "name": "input symbol for latin letters",
+ "shortname": ":abc:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-square"],
+ "moji": "🔤"
+ },
+ "abcd": {
+ "unicode": "1F521",
+ "unicode_alternates": [],
+ "name": "input symbol for latin small letters",
+ "shortname": ":abcd:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-square"],
+ "moji": "🔡"
+ },
+ "accept": {
+ "unicode": "1F251",
+ "unicode_alternates": [],
+ "name": "circled ideograph accept",
+ "shortname": ":accept:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["agree", "chinese", "good", "kanji", "ok", "yes"],
+ "moji": "🉑"
+ },
+ "aerial_tramway": {
+ "unicode": "1F6A1",
+ "unicode_alternates": [],
+ "name": "aerial tramway",
+ "shortname": ":aerial_tramway:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "aerial", "tram", "tramway", "cable", "transport"],
+ "moji": "🚡"
+ },
+ "airplane": {
+ "unicode": "2708",
+ "unicode_alternates": ["2708-FE0F"],
+ "name": "airplane",
+ "shortname": ":airplane:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flight", "transportation", "vehicle", "airplane", "plane", "airport", "travel", "airlines", "fly", "jet", "jumbo", "boeing", "airbus"],
+ "moji": "✈"
+ },
+ "airplane_arriving": {
+ "unicode": "1F6EC",
+ "unicode_alternates": [],
+ "name": "airplane arriving",
+ "shortname": ":airplane_arriving:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flight", "transportation", "vehicle", "plane", "airport", "travel", "airlines", "fly", "jet", "jumbo", "boeing", "airbus"]
+ },
+ "airplane_departure": {
+ "unicode": "1F6EB",
+ "unicode_alternates": [],
+ "name": "airplane departure",
+ "shortname": ":airplane_departure:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flight", "transportation", "vehicle", "plane", "airport", "travel", "airlines", "fly", "jet", "jumbo", "boeing", "airbus", "leaving"]
+ },
+ "airplane_northeast": {
+ "unicode": "1F6EA",
+ "unicode_alternates": [],
+ "name": "northeast-pointing airplane",
+ "shortname": ":airplane_northeast:",
+ "category": "travel_places",
+ "aliases": [":northeast_pointing_airplane:"],
+ "aliases_ascii": [],
+ "keywords": ["plane", "travel"]
+ },
+ "airplane_small": {
+ "unicode": "1F6E9",
+ "unicode_alternates": [],
+ "name": "small airplane",
+ "shortname": ":airplane_small:",
+ "category": "travel_places",
+ "aliases": [":small_airplane:"],
+ "aliases_ascii": [],
+ "keywords": ["flight", "transportation", "vehicle", "plane", "airport", "travel", "airlines", "fly", "jet", "jumbo", "boeing", "airbus"]
+ },
+ "airplane_small_up": {
+ "unicode": "1F6E8",
+ "unicode_alternates": [],
+ "name": "up-pointing small airplane",
+ "shortname": ":airplane_small_up:",
+ "category": "travel_places",
+ "aliases": [":up_pointing_small_airplane:"],
+ "aliases_ascii": [],
+ "keywords": ["plane", "travel"]
+ },
+ "airplane_up": {
+ "unicode": "1F6E7",
+ "unicode_alternates": [],
+ "name": "up-pointing airplane",
+ "shortname": ":airplane_up:",
+ "category": "travel_places",
+ "aliases": [":up_pointing_airplane:"],
+ "aliases_ascii": [],
+ "keywords": ["plane", "travel"]
+ },
+ "alarm_clock": {
+ "unicode": "23F0",
+ "unicode_alternates": [],
+ "name": "alarm clock",
+ "shortname": ":alarm_clock:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["time", "wake"],
+ "moji": "⏰"
+ },
+ "alien": {
+ "unicode": "1F47D",
+ "unicode_alternates": [],
+ "name": "extraterrestrial alien",
+ "shortname": ":alien:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["UFO", "paul", "alien", "ufo"],
+ "moji": "👽"
+ },
+ "ambulance": {
+ "unicode": "1F691",
+ "unicode_alternates": [],
+ "name": "ambulance",
+ "shortname": ":ambulance:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["911", "health", "ambulance", "emergency", "medical", "help", "assistance"],
+ "moji": "🚑"
+ },
+ "anchor": {
+ "unicode": "2693",
+ "unicode_alternates": ["2693-FE0F"],
+ "name": "anchor",
+ "shortname": ":anchor:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ferry", "ship", "anchor", "ship", "boat", "ocean", "harbor", "marina", "shipyard", "sailor", "tattoo"],
+ "moji": "⚓"
+ },
+ "angel": {
+ "unicode": "1F47C",
+ "unicode_alternates": [],
+ "name": "baby angel",
+ "shortname": ":angel:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["baby", "angel", "halo", "cupid", "wings", "halo", "heaven", "wings", "jesus"],
+ "moji": "👼"
+ },
+ "anger": {
+ "unicode": "1F4A2",
+ "unicode_alternates": [],
+ "name": "anger symbol",
+ "shortname": ":anger:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["anger", "angry", "mad"],
+ "moji": "💢"
+ },
+ "anger_left": {
+ "unicode": "1F5EE",
+ "unicode_alternates": [],
+ "name": "left anger bubble",
+ "shortname": ":anger_left:",
+ "category": "objects_symbols",
+ "aliases": [":left_anger_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["speech", "balloon", "talk", "mood", "conversation", "communication", "comic", "angry"]
+ },
+ "anger_right": {
+ "unicode": "1F5EF",
+ "unicode_alternates": [],
+ "name": "right anger bubble",
+ "shortname": ":anger_right:",
+ "category": "objects_symbols",
+ "aliases": [":right_anger_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["speech", "balloon", "talk", "mood", "conversation", "communication", "comic", "angry"]
+ },
+ "angry": {
+ "unicode": "1F620",
+ "unicode_alternates": [],
+ "name": "angry face",
+ "shortname": ":angry:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [">:(", ">:-(", ":@"],
+ "keywords": ["angry", "livid", "mad", "vexed", "irritated", "annoyed", "face", "frustrated", "mad"],
+ "moji": "😠"
+ },
+ "anguished": {
+ "unicode": "1F627",
+ "unicode_alternates": [],
+ "name": "anguished face",
+ "shortname": ":anguished:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "nervous", "stunned", "pain", "anguish", "ouch", "misery", "distress", "grief"],
+ "moji": "😧"
+ },
+ "ant": {
+ "unicode": "1F41C",
+ "unicode_alternates": [],
+ "name": "ant",
+ "shortname": ":ant:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "insect", "ant", "queen", "insect", "team"],
+ "moji": "🐜"
+ },
+ "apple": {
+ "unicode": "1F34E",
+ "unicode_alternates": [],
+ "name": "red apple",
+ "shortname": ":apple:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fruit", "mac", "apple", "fruit", "electronics", "red", "doctor", "teacher", "school", "core"],
+ "moji": "🍎"
+ },
+ "aquarius": {
+ "unicode": "2652",
+ "unicode_alternates": ["2652-FE0F"],
+ "name": "aquarius",
+ "shortname": ":aquarius:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["aquarius", "water", "bearer", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "purple-square", "sign", "zodiac", "horoscope"],
+ "moji": "♒"
+ },
+ "aries": {
+ "unicode": "2648",
+ "unicode_alternates": ["2648-FE0F"],
+ "name": "aries",
+ "shortname": ":aries:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["aries", "ram", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "purple-square", "sign", "zodiac", "horoscope"],
+ "moji": "♈"
+ },
+ "arrow_backward": {
+ "unicode": "25C0",
+ "unicode_alternates": ["25C0-FE0F"],
+ "name": "black left-pointing triangle",
+ "shortname": ":arrow_backward:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "◀"
+ },
+ "arrow_double_down": {
+ "unicode": "23EC",
+ "unicode_alternates": [],
+ "name": "black down-pointing double triangle",
+ "shortname": ":arrow_double_down:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "⏬"
+ },
+ "arrow_double_up": {
+ "unicode": "23EB",
+ "unicode_alternates": [],
+ "name": "black up-pointing double triangle",
+ "shortname": ":arrow_double_up:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "⏫"
+ },
+ "arrow_down": {
+ "unicode": "2B07",
+ "unicode_alternates": ["2B07-FE0F"],
+ "name": "downwards black arrow",
+ "shortname": ":arrow_down:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "⬇"
+ },
+ "arrow_down_small": {
+ "unicode": "1F53D",
+ "unicode_alternates": [],
+ "name": "down-pointing small red triangle",
+ "shortname": ":arrow_down_small:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "🔽"
+ },
+ "arrow_forward": {
+ "unicode": "25B6",
+ "unicode_alternates": ["25B6-FE0F"],
+ "name": "black right-pointing triangle",
+ "shortname": ":arrow_forward:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "▶"
+ },
+ "arrow_heading_down": {
+ "unicode": "2935",
+ "unicode_alternates": ["2935-FE0F"],
+ "name": "arrow pointing rightwards then curving downwards",
+ "shortname": ":arrow_heading_down:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "⤵"
+ },
+ "arrow_heading_up": {
+ "unicode": "2934",
+ "unicode_alternates": ["2934-FE0F"],
+ "name": "arrow pointing rightwards then curving upwards",
+ "shortname": ":arrow_heading_up:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "⤴"
+ },
+ "arrow_left": {
+ "unicode": "2B05",
+ "unicode_alternates": ["2B05-FE0F"],
+ "name": "leftwards black arrow",
+ "shortname": ":arrow_left:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square", "previous"],
+ "moji": "⬅"
+ },
+ "arrow_lower_left": {
+ "unicode": "2199",
+ "unicode_alternates": ["2199-FE0F"],
+ "name": "south west arrow",
+ "shortname": ":arrow_lower_left:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "↙"
+ },
+ "arrow_lower_right": {
+ "unicode": "2198",
+ "unicode_alternates": ["2198-FE0F"],
+ "name": "south east arrow",
+ "shortname": ":arrow_lower_right:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "blue-square"],
+ "moji": "↘"
+ },
+ "arrow_right": {
+ "unicode": "27A1",
+ "unicode_alternates": ["27A1-FE0F"],
+ "name": "black rightwards arrow",
+ "shortname": ":arrow_right:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "next"],
+ "moji": "➡"
+ },
+ "arrow_right_hook": {
+ "unicode": "21AA",
+ "unicode_alternates": ["21AA-FE0F"],
+ "name": "rightwards arrow with hook",
+ "shortname": ":arrow_right_hook:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "↪"
+ },
+ "arrow_up": {
+ "unicode": "2B06",
+ "unicode_alternates": ["2B06-FE0F"],
+ "name": "upwards black arrow",
+ "shortname": ":arrow_up:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "⬆"
+ },
+ "arrow_up_down": {
+ "unicode": "2195",
+ "unicode_alternates": ["2195-FE0F"],
+ "name": "up down arrow",
+ "shortname": ":arrow_up_down:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "↕"
+ },
+ "arrow_up_small": {
+ "unicode": "1F53C",
+ "unicode_alternates": [],
+ "name": "up-pointing small red triangle",
+ "shortname": ":arrow_up_small:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "🔼"
+ },
+ "arrow_upper_left": {
+ "unicode": "2196",
+ "unicode_alternates": ["2196-FE0F"],
+ "name": "north west arrow",
+ "shortname": ":arrow_upper_left:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "↖"
+ },
+ "arrow_upper_right": {
+ "unicode": "2197",
+ "unicode_alternates": ["2197-FE0F"],
+ "name": "north east arrow",
+ "shortname": ":arrow_upper_right:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "↗"
+ },
+ "arrows_clockwise": {
+ "unicode": "1F503",
+ "unicode_alternates": [],
+ "name": "clockwise downwards and upwards open circle arrows",
+ "shortname": ":arrows_clockwise:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sync"],
+ "moji": "🔃"
+ },
+ "arrows_counterclockwise": {
+ "unicode": "1F504",
+ "unicode_alternates": [],
+ "name": "anticlockwise downwards and upwards open circle ar",
+ "shortname": ":arrows_counterclockwise:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "sync"],
+ "moji": "🔄"
+ },
+ "art": {
+ "unicode": "1F3A8",
+ "unicode_alternates": [],
+ "name": "artist palette",
+ "shortname": ":art:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["design", "draw", "paint", "artist", "palette", "art", "colors", "paint", "draw", "brush", "pastels", "oils"],
+ "moji": "🎨"
+ },
+ "articulated_lorry": {
+ "unicode": "1F69B",
+ "unicode_alternates": [],
+ "name": "articulated lorry",
+ "shortname": ":articulated_lorry:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "transportation", "vehicle", "truck", "delivery", "semi", "lorry", "articulated"],
+ "moji": "🚛"
+ },
+ "ascending_notes": {
+ "unicode": "1F39C",
+ "unicode_alternates": [],
+ "name": "beamed ascending musical notes",
+ "shortname": ":ascending_notes:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["score", "music", "sound", "tone"]
+ },
+ "astonished": {
+ "unicode": "1F632",
+ "unicode_alternates": [],
+ "name": "astonished face",
+ "shortname": ":astonished:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "xox", "shocked", "surprise", "astonished"],
+ "moji": "😲"
+ },
+ "athletic_shoe": {
+ "unicode": "1F45F",
+ "unicode_alternates": [],
+ "name": "athletic shoe",
+ "shortname": ":athletic_shoe:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shoes", "sports"],
+ "moji": "👟"
+ },
+ "atm": {
+ "unicode": "1F3E7",
+ "unicode_alternates": [],
+ "name": "automated teller machine",
+ "shortname": ":atm:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["atm", "cash", "withdrawal", "money", "deposit", "financial", "bank", "adam", "payday", "bank", "blue-square", "cash", "money", "payment"],
+ "moji": "🏧"
+ },
+ "b": {
+ "unicode": "1F171",
+ "unicode_alternates": [],
+ "name": "negative squared latin capital letter b",
+ "shortname": ":b:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "letter", "red-square"],
+ "moji": "🅱"
+ },
+ "baby": {
+ "unicode": "1F476",
+ "unicode_alternates": [],
+ "name": "baby",
+ "shortname": ":baby:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["boy", "child", "infant"],
+ "moji": "👶"
+ },
+ "baby_bottle": {
+ "unicode": "1F37C",
+ "unicode_alternates": [],
+ "name": "baby bottle",
+ "shortname": ":baby_bottle:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["container", "food", "baby", "bottle", "milk", "mother", "nipple", "newborn", "formula"],
+ "moji": "🍼"
+ },
+ "baby_chick": {
+ "unicode": "1F424",
+ "unicode_alternates": [],
+ "name": "baby chick",
+ "shortname": ":baby_chick:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "chicken", "chick", "baby", "bird", "chicken", "young", "woman", "cute"],
+ "moji": "🐤"
+ },
+ "baby_symbol": {
+ "unicode": "1F6BC",
+ "unicode_alternates": [],
+ "name": "baby symbol",
+ "shortname": ":baby_symbol:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["child", "orange-square", "baby", "crawl", "newborn", "human", "diaper", "small", "babe"],
+ "moji": "🚼"
+ },
+ "back": {
+ "unicode": "1F519",
+ "unicode_alternates": [],
+ "name": "back with leftwards arrow above",
+ "shortname": ":back:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow"],
+ "moji": "🔙"
+ },
+ "baggage_claim": {
+ "unicode": "1F6C4",
+ "unicode_alternates": [],
+ "name": "baggage claim",
+ "shortname": ":baggage_claim:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["airport", "blue-square", "transport", "bag", "baggage", "luggage", "travel"],
+ "moji": "🛄"
+ },
+ "balloon": {
+ "unicode": "1F388",
+ "unicode_alternates": [],
+ "name": "balloon",
+ "shortname": ":balloon:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["celebration", "party", "balloon", "birthday", "celebration", "helium", "gas", "children", "float"],
+ "moji": "🎈"
+ },
+ "ballot_box": {
+ "unicode": "1F5F3",
+ "unicode_alternates": [],
+ "name": "ballot box with ballot",
+ "shortname": ":ballot_box:",
+ "category": "objects_symbols",
+ "aliases": [":ballot_box_with_ballot:"],
+ "aliases_ascii": [],
+ "keywords": ["vote"]
+ },
+ "ballot_box_check": {
+ "unicode": "1F5F9",
+ "unicode_alternates": [],
+ "name": "ballot box with bold check",
+ "shortname": ":ballot_box_check:",
+ "category": "objects_symbols",
+ "aliases": [":ballot_box_with_bold_check:"],
+ "aliases_ascii": [],
+ "keywords": ["mark", "vote"]
+ },
+ "ballot_box_with_check": {
+ "unicode": "2611",
+ "unicode_alternates": ["2611-FE0F"],
+ "name": "ballot box with check",
+ "shortname": ":ballot_box_with_check:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["agree", "ok"],
+ "moji": "☑"
+ },
+ "ballot_box_x": {
+ "unicode": "1F5F5",
+ "unicode_alternates": [],
+ "name": "ballot box with script x",
+ "shortname": ":ballot_box_x:",
+ "category": "objects_symbols",
+ "aliases": [":ballot_box_with_script_x:"],
+ "aliases_ascii": [],
+ "keywords": ["mark", "vote"]
+ },
+ "ballot_x": {
+ "unicode": "1F5F4",
+ "unicode_alternates": [],
+ "name": "ballot script x",
+ "shortname": ":ballot_x:",
+ "category": "objects_symbols",
+ "aliases": [":ballot_script_x:"],
+ "aliases_ascii": [],
+ "keywords": ["mark", "vote"]
+ },
+ "bamboo": {
+ "unicode": "1F38D",
+ "unicode_alternates": [],
+ "name": "pine decoration",
+ "shortname": ":bamboo:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "vegetable", "pine", "bamboo", "decoration", "new", "years", "spirits", "harvest", "prosperity", "longevity", "fortune", "luck", "welcome", "farming", "agriculture"],
+ "moji": "🎍"
+ },
+ "banana": {
+ "unicode": "1F34C",
+ "unicode_alternates": [],
+ "name": "banana",
+ "shortname": ":banana:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "banana", "peel", "bunch"],
+ "moji": "🍌"
+ },
+ "bangbang": {
+ "unicode": "203C",
+ "unicode_alternates": ["203C-FE0F"],
+ "name": "double exclamation mark",
+ "shortname": ":bangbang:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["exclamation", "surprise"],
+ "moji": "‼"
+ },
+ "bank": {
+ "unicode": "1F3E6",
+ "unicode_alternates": [],
+ "name": "bank",
+ "shortname": ":bank:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building"],
+ "moji": "🏦"
+ },
+ "bar_chart": {
+ "unicode": "1F4CA",
+ "unicode_alternates": [],
+ "name": "bar chart",
+ "shortname": ":bar_chart:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph", "presentation", "stats"],
+ "moji": "📊"
+ },
+ "barber": {
+ "unicode": "1F488",
+ "unicode_alternates": [],
+ "name": "barber pole",
+ "shortname": ":barber:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hair", "salon", "style"],
+ "moji": "💈"
+ },
+ "baseball": {
+ "unicode": "26BE",
+ "unicode_alternates": ["26BE-FE0F"],
+ "name": "baseball",
+ "shortname": ":baseball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["MLB", "balls", "sports"],
+ "moji": "⚾"
+ },
+ "basketball": {
+ "unicode": "1F3C0",
+ "unicode_alternates": [],
+ "name": "basketball and hoop",
+ "shortname": ":basketball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["NBA", "balls", "sports", "basketball", "bball", "dribble", "hoop", "net", "swish", "rip city"],
+ "moji": "🏀"
+ },
+ "bath": {
+ "unicode": "1F6C0",
+ "unicode_alternates": [],
+ "name": "bath",
+ "shortname": ":bath:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clean", "shower", "bath", "tub", "basin", "wash", "bubble", "soak", "bathroom", "soap", "water", "clean", "shampoo", "lather", "water"],
+ "moji": "🛀"
+ },
+ "bathtub": {
+ "unicode": "1F6C1",
+ "unicode_alternates": [],
+ "name": "bathtub",
+ "shortname": ":bathtub:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clean", "shower", "bath", "tub", "basin", "wash", "bubble", "soak", "bathroom", "soap", "water", "clean", "shampoo", "lather", "water"],
+ "moji": "🛁"
+ },
+ "battery": {
+ "unicode": "1F50B",
+ "unicode_alternates": [],
+ "name": "battery",
+ "shortname": ":battery:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["energy", "power", "sustain"],
+ "moji": "🔋"
+ },
+ "beach": {
+ "unicode": "1F3D6",
+ "unicode_alternates": [],
+ "name": "beach with umbrella",
+ "shortname": ":beach:",
+ "category": "travel_places",
+ "aliases": [":beach_with_umbrella:"],
+ "aliases_ascii": [],
+ "keywords": ["sand", "sun", "surf", "vacation", "relaxation", "tanning", "tan", "swimming"]
+ },
+ "bear": {
+ "unicode": "1F43B",
+ "unicode_alternates": [],
+ "name": "bear face",
+ "shortname": ":bear:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐻"
+ },
+ "bed": {
+ "unicode": "1F6CF",
+ "unicode_alternates": [],
+ "name": "bed",
+ "shortname": ":bed:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sleep", "sex", "queen", "full", "twin", "king", "mattress"]
+ },
+ "bee": {
+ "unicode": "1F41D",
+ "unicode_alternates": [],
+ "name": "honeybee",
+ "shortname": ":bee:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "insect", "bee", "queen", "buzz", "flower", "pollen", "sting", "honey", "hive", "bumble", "pollination"],
+ "moji": "🐝"
+ },
+ "beer": {
+ "unicode": "1F37A",
+ "unicode_alternates": [],
+ "name": "beer mug",
+ "shortname": ":beer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beverage", "drink", "drunk", "party", "pub", "relax", "beer", "hops", "mug", "barley", "malt", "yeast", "portland", "oregon", "brewery", "micro", "pint", "boot"],
+ "moji": "🍺"
+ },
+ "beers": {
+ "unicode": "1F37B",
+ "unicode_alternates": [],
+ "name": "clinking beer mugs",
+ "shortname": ":beers:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beverage", "drink", "drunk", "party", "pub", "relax", "beer", "beers", "cheers", "mug", "toast", "celebrate", "pub", "bar", "jolly", "hops", "clink"],
+ "moji": "🍻"
+ },
+ "beetle": {
+ "unicode": "1F41E",
+ "unicode_alternates": [],
+ "name": "lady beetle",
+ "shortname": ":beetle:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["insect", "nature", "lady", "bug", "ladybug", "ladybird", "beetle", "cow", "lady cow", "insect", "endearment"],
+ "moji": "🐞"
+ },
+ "beginner": {
+ "unicode": "1F530",
+ "unicode_alternates": [],
+ "name": "japanese symbol for beginner",
+ "shortname": ":beginner:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["badge", "shield"],
+ "moji": "🔰"
+ },
+ "bell": {
+ "unicode": "1F514",
+ "unicode_alternates": [],
+ "name": "bell",
+ "shortname": ":bell:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chime", "christmas", "notification", "sound", "xmas"],
+ "moji": "🔔"
+ },
+ "bellhop": {
+ "unicode": "1F6CE",
+ "unicode_alternates": [],
+ "name": "bellhop bell",
+ "shortname": ":bellhop:",
+ "category": "travel_places",
+ "aliases": [":bellhop_bell:"],
+ "aliases_ascii": [],
+ "keywords": ["hotel", "porter", "ding"]
+ },
+ "bento": {
+ "unicode": "1F371",
+ "unicode_alternates": [],
+ "name": "bento box",
+ "shortname": ":bento:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["box", "food", "japanese", "bento", "japanese", "rice", "meal", "box", "obento", "convenient", "lunchbox"],
+ "moji": "🍱"
+ },
+ "bicyclist": {
+ "unicode": "1F6B4",
+ "unicode_alternates": [],
+ "name": "bicyclist",
+ "shortname": ":bicyclist:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bike", "exercise", "hipster", "sports", "bicyclist", "road", "bike", "pedal", "bicycle", "transportation"],
+ "moji": "🚴"
+ },
+ "bike": {
+ "unicode": "1F6B2",
+ "unicode_alternates": [],
+ "name": "bicycle",
+ "shortname": ":bike:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bicycle", "exercise", "hipster", "sports", "bike", "pedal", "bicycle", "transportation"],
+ "moji": "🚲"
+ },
+ "bikini": {
+ "unicode": "1F459",
+ "unicode_alternates": [],
+ "name": "bikini",
+ "shortname": ":bikini:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beach", "fashion", "female", "girl", "swimming", "woman"],
+ "moji": "👙"
+ },
+ "bird": {
+ "unicode": "1F426",
+ "unicode_alternates": [],
+ "name": "bird",
+ "shortname": ":bird:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "fly", "nature", "tweet"],
+ "moji": "🐦"
+ },
+ "birthday": {
+ "unicode": "1F382",
+ "unicode_alternates": [],
+ "name": "birthday cake",
+ "shortname": ":birthday:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cake", "party", "birthday", "birth", "cake", "dessert", "wish", "celebrate"],
+ "moji": "🎂"
+ },
+ "black_circle": {
+ "unicode": "26AB",
+ "unicode_alternates": ["26AB-FE0F"],
+ "name": "medium black circle",
+ "shortname": ":black_circle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "⚫"
+ },
+ "black_joker": {
+ "unicode": "1F0CF",
+ "unicode_alternates": [],
+ "name": "playing card black joker",
+ "shortname": ":black_joker:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cards", "game", "poker"],
+ "moji": "🃏"
+ },
+ "black_large_square": {
+ "unicode": "2B1B",
+ "unicode_alternates": ["2B1B-FE0F"],
+ "name": "black large square",
+ "shortname": ":black_large_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "⬛"
+ },
+ "black_medium_small_square": {
+ "unicode": "25FE",
+ "unicode_alternates": ["25FE-FE0F"],
+ "name": "black medium small square",
+ "shortname": ":black_medium_small_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "◾"
+ },
+ "black_medium_square": {
+ "unicode": "25FC",
+ "unicode_alternates": ["25FC-FE0F"],
+ "name": "black medium square",
+ "shortname": ":black_medium_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "◼"
+ },
+ "black_nib": {
+ "unicode": "2712",
+ "unicode_alternates": ["2712-FE0F"],
+ "name": "black nib",
+ "shortname": ":black_nib:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["pen", "stationery"],
+ "moji": "✒"
+ },
+ "black_small_square": {
+ "unicode": "25AA",
+ "unicode_alternates": ["25AA-FE0F"],
+ "name": "black small square",
+ "shortname": ":black_small_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "▪"
+ },
+ "black_square_button": {
+ "unicode": "1F532",
+ "unicode_alternates": [],
+ "name": "black square button",
+ "shortname": ":black_square_button:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["frame"],
+ "moji": "🔲"
+ },
+ "blossom": {
+ "unicode": "1F33C",
+ "unicode_alternates": [],
+ "name": "blossom",
+ "shortname": ":blossom:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flowers", "nature", "yellow", "blossom", "daisy", "flower"],
+ "moji": "🌼"
+ },
+ "blowfish": {
+ "unicode": "1F421",
+ "unicode_alternates": [],
+ "name": "blowfish",
+ "shortname": ":blowfish:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "nature", "ocean", "sea", "blowfish", "pufferfish", "puffer", "ballonfish", "toadfish", "fugu fish", "sushi"],
+ "moji": "🐡"
+ },
+ "blue_book": {
+ "unicode": "1F4D8",
+ "unicode_alternates": [],
+ "name": "blue book",
+ "shortname": ":blue_book:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["knowledge", "library", "read"],
+ "moji": "📘"
+ },
+ "blue_car": {
+ "unicode": "1F699",
+ "unicode_alternates": [],
+ "name": "recreational vehicle",
+ "shortname": ":blue_car:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["car", "suv", "car", "wagon", "automobile"],
+ "moji": "🚙"
+ },
+ "blue_heart": {
+ "unicode": "1F499",
+ "unicode_alternates": [],
+ "name": "blue heart",
+ "shortname": ":blue_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "blue", "heart", "love", "stability", "truth", "loyalty", "trust"],
+ "moji": "💙"
+ },
+ "blush": {
+ "unicode": "1F60A",
+ "unicode_alternates": [],
+ "name": "smiling face with smiling eyes",
+ "shortname": ":blush:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["crush", "embarrassed", "face", "flushed", "happy", "shy", "smile", "smiling", "smile", "smiley"],
+ "moji": "😊"
+ },
+ "boar": {
+ "unicode": "1F417",
+ "unicode_alternates": [],
+ "name": "boar",
+ "shortname": ":boar:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐗"
+ },
+ "bomb": {
+ "unicode": "1F4A3",
+ "unicode_alternates": [],
+ "name": "bomb",
+ "shortname": ":bomb:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["boom", "explode"],
+ "moji": "💣"
+ },
+ "book": {
+ "unicode": "1F4D6",
+ "unicode_alternates": [],
+ "name": "open book",
+ "shortname": ":book:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["library", "literature"],
+ "moji": "📖"
+ },
+ "book2": {
+ "unicode": "1F56E",
+ "unicode_alternates": [],
+ "name": "book",
+ "shortname": ":book2:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["library", "literature", "novel", "reading", "story"]
+ },
+ "bookmark": {
+ "unicode": "1F516",
+ "unicode_alternates": [],
+ "name": "bookmark",
+ "shortname": ":bookmark:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["favorite"],
+ "moji": "🔖"
+ },
+ "bookmark_tabs": {
+ "unicode": "1F4D1",
+ "unicode_alternates": [],
+ "name": "bookmark tabs",
+ "shortname": ":bookmark_tabs:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["favorite"],
+ "moji": "📑"
+ },
+ "books": {
+ "unicode": "1F4DA",
+ "unicode_alternates": [],
+ "name": "books",
+ "shortname": ":books:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["library", "literature"],
+ "moji": "📚"
+ },
+ "boom": {
+ "unicode": "1F4A5",
+ "unicode_alternates": [],
+ "name": "collision symbol",
+ "shortname": ":boom:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bomb", "explode", "explosion", "boom", "bang", "collision", "fire", "emphasis", "wow", "bam"],
+ "moji": "💥"
+ },
+ "boot": {
+ "unicode": "1F462",
+ "unicode_alternates": [],
+ "name": "womans boots",
+ "shortname": ":boot:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "shoes"],
+ "moji": "👢"
+ },
+ "bouquet": {
+ "unicode": "1F490",
+ "unicode_alternates": [],
+ "name": "bouquet",
+ "shortname": ":bouquet:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flowers", "nature"],
+ "moji": "💐"
+ },
+ "bouquet2": {
+ "unicode": "1F395",
+ "unicode_alternates": [],
+ "name": "bouquet of flowers",
+ "shortname": ":bouquet2:",
+ "category": "celebration",
+ "aliases": [":bouquet_of_flowers:"],
+ "aliases_ascii": [],
+ "keywords": ["nature", "marriage", "wedding", "bride"]
+ },
+ "bow": {
+ "unicode": "1F647",
+ "unicode_alternates": [],
+ "name": "person bowing deeply",
+ "shortname": ":bow:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["boy", "male", "man", "sorry", "bow", "respect", "curtsy", "bend"],
+ "moji": "🙇"
+ },
+ "bowling": {
+ "unicode": "1F3B3",
+ "unicode_alternates": [],
+ "name": "bowling",
+ "shortname": ":bowling:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fun", "play", "sports", "bowl", "bowling", "ball", "pin", "strike", "spare", "game"],
+ "moji": "🎳"
+ },
+ "boy": {
+ "unicode": "1F466",
+ "unicode_alternates": [],
+ "name": "boy",
+ "shortname": ":boy:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["guy", "male", "man"],
+ "moji": "👦"
+ },
+ "boys_symbol": {
+ "unicode": "1F6C9",
+ "unicode_alternates": [],
+ "name": "boys symbol",
+ "shortname": ":boys_symbol:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["male", "child"]
+ },
+ "bread": {
+ "unicode": "1F35E",
+ "unicode_alternates": [],
+ "name": "bread",
+ "shortname": ":bread:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["breakfast", "food", "toast", "wheat", "bread", "loaf", "yeast"],
+ "moji": "🍞"
+ },
+ "bride_with_veil": {
+ "unicode": "1F470",
+ "unicode_alternates": [],
+ "name": "bride with veil",
+ "shortname": ":bride_with_veil:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["couple", "marriage", "wedding", "bride", "wedding", "planning", "veil", "gown", "dress", "engagement", "white"],
+ "moji": "👰"
+ },
+ "bridge_at_night": {
+ "unicode": "1F309",
+ "unicode_alternates": [],
+ "name": "bridge at night",
+ "shortname": ":bridge_at_night:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "sanfrancisco", "bridge", "night", "water", "road", "evening", "suspension", "golden", "gate"],
+ "moji": "🌉"
+ },
+ "briefcase": {
+ "unicode": "1F4BC",
+ "unicode_alternates": [],
+ "name": "briefcase",
+ "shortname": ":briefcase:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["business", "documents", "work"],
+ "moji": "💼"
+ },
+ "broken_heart": {
+ "unicode": "1F494",
+ "unicode_alternates": [],
+ "name": "broken heart",
+ "shortname": ":broken_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["</3"],
+ "keywords": ["sad", "sorry"],
+ "moji": "💔"
+ },
+ "bug": {
+ "unicode": "1F41B",
+ "unicode_alternates": [],
+ "name": "bug",
+ "shortname": ":bug:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["insect", "nature", "bug", "insect", "virus", "error"],
+ "moji": "🐛"
+ },
+ "bulb": {
+ "unicode": "1F4A1",
+ "unicode_alternates": [],
+ "name": "electric light bulb",
+ "shortname": ":bulb:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["electricity", "light", "idea", "bulb", "light"],
+ "moji": "💡"
+ },
+ "bullettrain_front": {
+ "unicode": "1F685",
+ "unicode_alternates": [],
+ "name": "high-speed train with bullet nose",
+ "shortname": ":bullettrain_front:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "train", "bullet", "rail"],
+ "moji": "🚅"
+ },
+ "bullettrain_side": {
+ "unicode": "1F684",
+ "unicode_alternates": [],
+ "name": "high-speed train",
+ "shortname": ":bullettrain_side:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "train", "bullet", "rail"],
+ "moji": "🚄"
+ },
+ "bullhorn": {
+ "unicode": "1F56B",
+ "unicode_alternates": [],
+ "name": "bullhorn",
+ "shortname": ":bullhorn:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "noise", "announcement", "megaphone"]
+ },
+ "bullhorn_waves": {
+ "unicode": "1F56C",
+ "unicode_alternates": [],
+ "name": "bullhorn with sound waves",
+ "shortname": ":bullhorn_waves:",
+ "category": "objects_symbols",
+ "aliases": [":bullhorn_with_sound_waves:"],
+ "aliases_ascii": [],
+ "keywords": ["sound", "noise", "announcement", "megaphone"]
+ },
+ "bus": {
+ "unicode": "1F68C",
+ "unicode_alternates": [],
+ "name": "bus",
+ "shortname": ":bus:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["car", "transportation", "vehicle", "bus", "school", "city", "transportation", "public"],
+ "moji": "🚌"
+ },
+ "busstop": {
+ "unicode": "1F68F",
+ "unicode_alternates": [],
+ "name": "bus stop",
+ "shortname": ":busstop:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "bus", "stop", "city", "transport", "transportation"],
+ "moji": "🚏"
+ },
+ "bust_in_silhouette": {
+ "unicode": "1F464",
+ "unicode_alternates": [],
+ "name": "bust in silhouette",
+ "shortname": ":bust_in_silhouette:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["human", "man", "person", "user", "silhouette", "person", "user", "member", "account", "guest", "icon", "avatar", "profile", "me", "myself", "i"],
+ "moji": "👤"
+ },
+ "busts_in_silhouette": {
+ "unicode": "1F465",
+ "unicode_alternates": [],
+ "name": "busts in silhouette",
+ "shortname": ":busts_in_silhouette:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["group", "human", "man", "person", "team", "user", "silhouette", "silhouettes", "people", "user", "members", "accounts", "relationship", "shadow"],
+ "moji": "👥"
+ },
+ "cactus": {
+ "unicode": "1F335",
+ "unicode_alternates": [],
+ "name": "cactus",
+ "shortname": ":cactus:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "vegetable", "cactus", "desert", "drought", "spike", "poke"],
+ "moji": "🌵"
+ },
+ "cake": {
+ "unicode": "1F370",
+ "unicode_alternates": [],
+ "name": "shortcake",
+ "shortname": ":cake:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "cake", "short", "dessert", "strawberry"],
+ "moji": "🍰"
+ },
+ "calculator": {
+ "unicode": "1F5A9",
+ "unicode_alternates": [],
+ "name": "pocket calculator",
+ "shortname": ":calculator:",
+ "category": "objects_symbols",
+ "aliases": [":pocket calculator:"],
+ "aliases_ascii": [],
+ "keywords": ["add", "subtract", "multiple", "divide", "scientific"]
+ },
+ "calendar": {
+ "unicode": "1F4C6",
+ "unicode_alternates": [],
+ "name": "tear-off calendar",
+ "shortname": ":calendar:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["schedule"],
+ "moji": "📆"
+ },
+ "calendar_spiral": {
+ "unicode": "1F5D3",
+ "unicode_alternates": [],
+ "name": "spiral calendar pad",
+ "shortname": ":calendar_spiral:",
+ "category": "objects_symbols",
+ "aliases": [":spiral_calendar_pad:"],
+ "aliases_ascii": [],
+ "keywords": ["schedule", "date", "day"]
+ },
+ "calling": {
+ "unicode": "1F4F2",
+ "unicode_alternates": [],
+ "name": "mobile phone with rightwards arrow at left",
+ "shortname": ":calling:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["incoming", "iphone"],
+ "moji": "📲"
+ },
+ "camel": {
+ "unicode": "1F42B",
+ "unicode_alternates": [],
+ "name": "bactrian camel",
+ "shortname": ":camel:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "hot", "nature", "bactrian", "camel", "hump", "desert", "central asia", "heat", "hot", "water", "hump day", "wednesday", "sex"],
+ "moji": "🐫"
+ },
+ "camera": {
+ "unicode": "1F4F7",
+ "unicode_alternates": [],
+ "name": "camera",
+ "shortname": ":camera:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gadgets", "photo"],
+ "moji": "📷"
+ },
+ "camera_with_flash": {
+ "unicode": "1F4F8",
+ "unicode_alternates": [],
+ "name": "camera with flash",
+ "shortname": ":camera_with_flash:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "picture"]
+ },
+ "camping": {
+ "unicode": "1F3D5",
+ "unicode_alternates": [],
+ "name": "camping",
+ "shortname": ":camping:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["outdoors", "nature", "wilderness", "roughing", "activity"]
+ },
+ "cancellation_x": {
+ "unicode": "1F5D9",
+ "unicode_alternates": [],
+ "name": "cancellation x",
+ "shortname": ":cancellation_x:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cancel", "stop", "delete"]
+ },
+ "cancer": {
+ "unicode": "264B",
+ "unicode_alternates": ["264B-FE0F"],
+ "name": "cancer",
+ "shortname": ":cancer:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cancer", "crab", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "sign", "zodiac", "horoscope"],
+ "moji": "♋"
+ },
+ "candle": {
+ "unicode": "1F56F",
+ "unicode_alternates": [],
+ "name": "candle",
+ "shortname": ":candle:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["light", "wax"]
+ },
+ "candy": {
+ "unicode": "1F36C",
+ "unicode_alternates": [],
+ "name": "candy",
+ "shortname": ":candy:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "snack", "candy", "sugar", "sweet", "hard"],
+ "moji": "🍬"
+ },
+ "capital_abcd": {
+ "unicode": "1F520",
+ "unicode_alternates": [],
+ "name": "input symbol for latin capital letters",
+ "shortname": ":capital_abcd:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-square", "words"],
+ "moji": "🔠"
+ },
+ "capricorn": {
+ "unicode": "2651",
+ "unicode_alternates": ["2651-FE0F"],
+ "name": "capricorn",
+ "shortname": ":capricorn:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["capricorn", "sea-goat", "goat-horned", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "sign", "zodiac", "horoscope"],
+ "moji": "♑"
+ },
+ "card_box": {
+ "unicode": "1F5C3",
+ "unicode_alternates": [],
+ "name": "card file box",
+ "shortname": ":card_box:",
+ "category": "objects_symbols",
+ "aliases": [":card_file_box:"],
+ "aliases_ascii": [],
+ "keywords": ["index", "organization"]
+ },
+ "card_index": {
+ "unicode": "1F4C7",
+ "unicode_alternates": [],
+ "name": "card index",
+ "shortname": ":card_index:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["business", "stationery"],
+ "moji": "📇"
+ },
+ "carousel_horse": {
+ "unicode": "1F3A0",
+ "unicode_alternates": [],
+ "name": "carousel horse",
+ "shortname": ":carousel_horse:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["carnival", "horse", "photo", "carousel", "horse", "amusement", "park", "ride", "entertainment", "park", "fair"],
+ "moji": "🎠"
+ },
+ "cartridge": {
+ "unicode": "1F5AD",
+ "unicode_alternates": [],
+ "name": "tape cartridge",
+ "shortname": ":cartridge:",
+ "category": "objects_symbols",
+ "aliases": [":tape_cartridge:"],
+ "aliases_ascii": [],
+ "keywords": ["oldschool", "save", "technology", "disk", "storage", "information", "computer", "drive", "megabyte"]
+ },
+ "cat": {
+ "unicode": "1F431",
+ "unicode_alternates": [],
+ "name": "cat face",
+ "shortname": ":cat:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "meow"],
+ "moji": "🐱"
+ },
+ "cat2": {
+ "unicode": "1F408",
+ "unicode_alternates": [],
+ "name": "cat",
+ "shortname": ":cat2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "meow", "pet", "cat", "kitten", "meow"],
+ "moji": "🐈"
+ },
+ "celtic_cross": {
+ "unicode": "1F548",
+ "unicode_alternates": [],
+ "name": "celtic cross",
+ "shortname": ":celtic_cross:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["religion", "symbol"]
+ },
+ "chart": {
+ "unicode": "1F4B9",
+ "unicode_alternates": [],
+ "name": "chart with upwards trend and yen sign",
+ "shortname": ":chart:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph", "green-square"],
+ "moji": "💹"
+ },
+ "chart_with_downwards_trend": {
+ "unicode": "1F4C9",
+ "unicode_alternates": [],
+ "name": "chart with downwards trend",
+ "shortname": ":chart_with_downwards_trend:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph"],
+ "moji": "📉"
+ },
+ "chart_with_upwards_trend": {
+ "unicode": "1F4C8",
+ "unicode_alternates": [],
+ "name": "chart with upwards trend",
+ "shortname": ":chart_with_upwards_trend:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph"],
+ "moji": "📈"
+ },
+ "checkered_flag": {
+ "unicode": "1F3C1",
+ "unicode_alternates": [],
+ "name": "chequered flag",
+ "shortname": ":checkered_flag:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["contest", "finishline", "gokart", "rase", "checkered", "chequred", "race", "flag", "finish", "complete", "end"],
+ "moji": "🏁"
+ },
+ "cherries": {
+ "unicode": "1F352",
+ "unicode_alternates": [],
+ "name": "cherries",
+ "shortname": ":cherries:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "cherry", "cherries", "tree", "fruit", "pit"],
+ "moji": "🍒"
+ },
+ "cherry_blossom": {
+ "unicode": "1F338",
+ "unicode_alternates": [],
+ "name": "cherry blossom",
+ "shortname": ":cherry_blossom:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flower", "nature", "plant", "cherry", "blossom", "tree", "flower"],
+ "moji": "🌸"
+ },
+ "chestnut": {
+ "unicode": "1F330",
+ "unicode_alternates": [],
+ "name": "chestnut",
+ "shortname": ":chestnut:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "squirrel", "chestnut", "roasted", "food", "tree"],
+ "moji": "🌰"
+ },
+ "chicken": {
+ "unicode": "1F414",
+ "unicode_alternates": [],
+ "name": "chicken",
+ "shortname": ":chicken:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cluck", "chicken", "hen", "poultry", "livestock"],
+ "moji": "🐔"
+ },
+ "children_crossing": {
+ "unicode": "1F6B8",
+ "unicode_alternates": [],
+ "name": "children crossing",
+ "shortname": ":children_crossing:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["school", "children", "kids", "caution", "crossing", "street", "crosswalk", "slow"],
+ "moji": "🚸"
+ },
+ "chipmunk": {
+ "unicode": "1F43F",
+ "unicode_alternates": [],
+ "name": "chipmunk",
+ "shortname": ":chipmunk:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"]
+ },
+ "chocolate_bar": {
+ "unicode": "1F36B",
+ "unicode_alternates": [],
+ "name": "chocolate bar",
+ "shortname": ":chocolate_bar:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "snack", "chocolate", "bar", "candy", "coca", "hershey&#039;s"],
+ "moji": "🍫"
+ },
+ "christmas_tree": {
+ "unicode": "1F384",
+ "unicode_alternates": [],
+ "name": "christmas tree",
+ "shortname": ":christmas_tree:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["celebration", "december", "festival", "vacation", "xmas", "christmas", "xmas", "santa", "holiday", "winter", "december", "santa", "evergreen", "ornaments", "jesus", "gifts", "presents"],
+ "moji": "🎄"
+ },
+ "church": {
+ "unicode": "26EA",
+ "unicode_alternates": ["26EA-FE0F"],
+ "name": "church",
+ "shortname": ":church:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "christ", "religion"],
+ "moji": "⛪"
+ },
+ "cinema": {
+ "unicode": "1F3A6",
+ "unicode_alternates": [],
+ "name": "cinema",
+ "shortname": ":cinema:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "film", "movie", "record", "cinema", "movie", "theater", "motion", "picture"],
+ "moji": "🎦"
+ },
+ "circus_tent": {
+ "unicode": "1F3AA",
+ "unicode_alternates": [],
+ "name": "circus tent",
+ "shortname": ":circus_tent:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["carnival", "festival", "party", "circus", "tent", "event", "carnival", "big", "top", "canvas"],
+ "moji": "🎪"
+ },
+ "city_dusk": {
+ "unicode": "1F306",
+ "unicode_alternates": [],
+ "name": "cityscape at dusk",
+ "shortname": ":city_dusk:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "city", "scape", "sunset", "dusk", "lights", "evening", "metropolitan", "night", "dark"],
+ "moji": "🌆"
+ },
+ "city_sunset": {
+ "unicode": "1F307",
+ "unicode_alternates": [],
+ "name": "sunset over buildings",
+ "shortname": ":city_sunset:",
+ "category": "places",
+ "aliases": [":city_sunrise:"],
+ "aliases_ascii": [],
+ "keywords": ["photo", "city", "scape", "sunrise", "dawn", "light", "morning", "metropolitan", "rise", "sun"],
+ "moji": "🌇"
+ },
+ "cityscape": {
+ "unicode": "1F3D9",
+ "unicode_alternates": [],
+ "name": "cityscape",
+ "shortname": ":cityscape:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["skyscraper", "city", "view", "lights", "buiildings", "metropolis"]
+ },
+ "clap": {
+ "unicode": "1F44F",
+ "unicode_alternates": [],
+ "name": "clapping hands sign",
+ "shortname": ":clap:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["applause", "congrats", "hands", "praise", "clapping", "appreciation", "approval", "sound", "encouragement", "enthusiasm"],
+ "moji": "👏"
+ },
+ "clapper": {
+ "unicode": "1F3AC",
+ "unicode_alternates": [],
+ "name": "clapper board",
+ "shortname": ":clapper:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["film", "movie", "record", "clapper", "board", "clapboard", "movie", "film", "take"],
+ "moji": "🎬"
+ },
+ "classical_building": {
+ "unicode": "1F3DB",
+ "unicode_alternates": [],
+ "name": "classical building",
+ "shortname": ":classical_building:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["government", "architecture", "history", "iconic", "genre"]
+ },
+ "clipboard": {
+ "unicode": "1F4CB",
+ "unicode_alternates": [],
+ "name": "clipboard",
+ "shortname": ":clipboard:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents", "stationery"],
+ "moji": "📋"
+ },
+ "clock": {
+ "unicode": "1F570",
+ "unicode_alternates": [],
+ "name": "mantlepiece clock",
+ "shortname": ":clock:",
+ "category": "objects_symbols",
+ "aliases": [":mantlepiece_clock:"],
+ "aliases_ascii": [],
+ "keywords": ["time"]
+ },
+ "clock1": {
+ "unicode": "1F550",
+ "unicode_alternates": [],
+ "name": "clock face one oclock",
+ "shortname": ":clock1:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕐"
+ },
+ "clock10": {
+ "unicode": "1F559",
+ "unicode_alternates": [],
+ "name": "clock face ten oclock",
+ "shortname": ":clock10:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕙"
+ },
+ "clock1030": {
+ "unicode": "1F565",
+ "unicode_alternates": [],
+ "name": "clock face ten-thirty",
+ "shortname": ":clock1030:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕥"
+ },
+ "clock11": {
+ "unicode": "1F55A",
+ "unicode_alternates": [],
+ "name": "clock face eleven oclock",
+ "shortname": ":clock11:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕚"
+ },
+ "clock1130": {
+ "unicode": "1F566",
+ "unicode_alternates": [],
+ "name": "clock face eleven-thirty",
+ "shortname": ":clock1130:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕦"
+ },
+ "clock12": {
+ "unicode": "1F55B",
+ "unicode_alternates": [],
+ "name": "clock face twelve oclock",
+ "shortname": ":clock12:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕛"
+ },
+ "clock1230": {
+ "unicode": "1F567",
+ "unicode_alternates": [],
+ "name": "clock face twelve-thirty",
+ "shortname": ":clock1230:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"]
+ },
+ "clock130": {
+ "unicode": "1F55C",
+ "unicode_alternates": [],
+ "name": "clock face one-thirty",
+ "shortname": ":clock130:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕜"
+ },
+ "clock2": {
+ "unicode": "1F551",
+ "unicode_alternates": [],
+ "name": "clock face two oclock",
+ "shortname": ":clock2:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕑"
+ },
+ "clock230": {
+ "unicode": "1F55D",
+ "unicode_alternates": [],
+ "name": "clock face two-thirty",
+ "shortname": ":clock230:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕝"
+ },
+ "clock3": {
+ "unicode": "1F552",
+ "unicode_alternates": [],
+ "name": "clock face three oclock",
+ "shortname": ":clock3:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕒"
+ },
+ "clock330": {
+ "unicode": "1F55E",
+ "unicode_alternates": [],
+ "name": "clock face three-thirty",
+ "shortname": ":clock330:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕞"
+ },
+ "clock4": {
+ "unicode": "1F553",
+ "unicode_alternates": [],
+ "name": "clock face four oclock",
+ "shortname": ":clock4:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕓"
+ },
+ "clock430": {
+ "unicode": "1F55F",
+ "unicode_alternates": [],
+ "name": "clock face four-thirty",
+ "shortname": ":clock430:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕟"
+ },
+ "clock5": {
+ "unicode": "1F554",
+ "unicode_alternates": [],
+ "name": "clock face five oclock",
+ "shortname": ":clock5:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕔"
+ },
+ "clock530": {
+ "unicode": "1F560",
+ "unicode_alternates": [],
+ "name": "clock face five-thirty",
+ "shortname": ":clock530:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕠"
+ },
+ "clock6": {
+ "unicode": "1F555",
+ "unicode_alternates": [],
+ "name": "clock face six oclock",
+ "shortname": ":clock6:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕕"
+ },
+ "clock630": {
+ "unicode": "1F561",
+ "unicode_alternates": [],
+ "name": "clock face six-thirty",
+ "shortname": ":clock630:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕡"
+ },
+ "clock7": {
+ "unicode": "1F556",
+ "unicode_alternates": [],
+ "name": "clock face seven oclock",
+ "shortname": ":clock7:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕖"
+ },
+ "clock730": {
+ "unicode": "1F562",
+ "unicode_alternates": [],
+ "name": "clock face seven-thirty",
+ "shortname": ":clock730:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕢"
+ },
+ "clock8": {
+ "unicode": "1F557",
+ "unicode_alternates": [],
+ "name": "clock face eight oclock",
+ "shortname": ":clock8:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕗"
+ },
+ "clock830": {
+ "unicode": "1F563",
+ "unicode_alternates": [],
+ "name": "clock face eight-thirty",
+ "shortname": ":clock830:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕣"
+ },
+ "clock9": {
+ "unicode": "1F558",
+ "unicode_alternates": [],
+ "name": "clock face nine oclock",
+ "shortname": ":clock9:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕘"
+ },
+ "clock930": {
+ "unicode": "1F564",
+ "unicode_alternates": [],
+ "name": "clock face nine-thirty",
+ "shortname": ":clock930:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "time"],
+ "moji": "🕤"
+ },
+ "clockwise_arrows": {
+ "unicode": "1F5D8",
+ "unicode_alternates": [],
+ "name": "clockwise right and left semicircle arrows",
+ "shortname": ":clockwise_arrows:",
+ "category": "objects_symbols",
+ "aliases": [":clockwise_right_and_left_semicircle_arrows:"],
+ "aliases_ascii": [],
+ "keywords": ["sync"]
+ },
+ "closed_book": {
+ "unicode": "1F4D5",
+ "unicode_alternates": [],
+ "name": "closed book",
+ "shortname": ":closed_book:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["knowledge", "library", "read"],
+ "moji": "📕"
+ },
+ "closed_lock_with_key": {
+ "unicode": "1F510",
+ "unicode_alternates": [],
+ "name": "closed lock with key",
+ "shortname": ":closed_lock_with_key:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["privacy", "security"],
+ "moji": "🔐"
+ },
+ "closed_umbrella": {
+ "unicode": "1F302",
+ "unicode_alternates": [],
+ "name": "closed umbrella",
+ "shortname": ":closed_umbrella:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["drizzle", "rain", "weather", "umbrella", "closed", "rain", "moisture", "protection", "sun", "ultraviolet", "uv"],
+ "moji": "🌂"
+ },
+ "cloud": {
+ "unicode": "2601",
+ "unicode_alternates": ["2601-FE0F"],
+ "name": "cloud",
+ "shortname": ":cloud:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sky", "weather"],
+ "moji": "☁"
+ },
+ "cloud_lightning": {
+ "unicode": "1F329",
+ "unicode_alternates": [],
+ "name": "cloud with lightning",
+ "shortname": ":cloud_lightning:",
+ "category": "nature",
+ "aliases": [":cloud_with_lightning:"],
+ "aliases_ascii": [],
+ "keywords": ["weather", "thunder"]
+ },
+ "cloud_rain": {
+ "unicode": "1F327",
+ "unicode_alternates": [],
+ "name": "cloud with rain",
+ "shortname": ":cloud_rain:",
+ "category": "nature",
+ "aliases": [":cloud_with_rain:"],
+ "aliases_ascii": [],
+ "keywords": ["weather", "wet"]
+ },
+ "cloud_snow": {
+ "unicode": "1F328",
+ "unicode_alternates": [],
+ "name": "cloud with snow",
+ "shortname": ":cloud_snow:",
+ "category": "nature",
+ "aliases": [":cloud_with_snow:"],
+ "aliases_ascii": [],
+ "keywords": ["weather", "cold"]
+ },
+ "cloud_tornado": {
+ "unicode": "1F32A",
+ "unicode_alternates": [],
+ "name": "cloud with tornado",
+ "shortname": ":cloud_tornado:",
+ "category": "nature",
+ "aliases": [":cloud_with_tornado:"],
+ "aliases_ascii": [],
+ "keywords": ["weather", "destruction", "funnel"]
+ },
+ "clubs": {
+ "unicode": "2663",
+ "unicode_alternates": ["2663-FE0F"],
+ "name": "black club suit",
+ "shortname": ":clubs:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cards", "poker"],
+ "moji": "♣"
+ },
+ "cocktail": {
+ "unicode": "1F378",
+ "unicode_alternates": [],
+ "name": "cocktail glass",
+ "shortname": ":cocktail:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alcohol", "beverage", "drink", "drunk", "cocktail", "mixed", "drink", "alcohol", "glass", "martini", "bar"],
+ "moji": "🍸"
+ },
+ "coffee": {
+ "unicode": "2615",
+ "unicode_alternates": ["2615-FE0F"],
+ "name": "hot beverage",
+ "shortname": ":coffee:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beverage", "cafe", "drink", "espresso"],
+ "moji": "☕"
+ },
+ "cold_sweat": {
+ "unicode": "1F630",
+ "unicode_alternates": [],
+ "name": "face with open mouth and cold sweat",
+ "shortname": ":cold_sweat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "nervous", "sweat", "exasperated", "frustrated"],
+ "moji": "😰"
+ },
+ "compression": {
+ "unicode": "1F5DC",
+ "unicode_alternates": [],
+ "name": "compression",
+ "shortname": ":compression:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["reduce"]
+ },
+ "computer": {
+ "unicode": "1F4BB",
+ "unicode_alternates": [],
+ "name": "personal computer",
+ "shortname": ":computer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["laptop", "tech"],
+ "moji": "💻"
+ },
+ "computer_old": {
+ "unicode": "1F5B3",
+ "unicode_alternates": [],
+ "name": "old personal computer",
+ "shortname": ":computer_old:",
+ "category": "objects_symbols",
+ "aliases": [":old_personal_computer:"],
+ "aliases_ascii": [],
+ "keywords": ["cpu", "terminal"]
+ },
+ "confetti_ball": {
+ "unicode": "1F38A",
+ "unicode_alternates": [],
+ "name": "confetti ball",
+ "shortname": ":confetti_ball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["festival", "party", "party", "congratulations", "confetti", "ball", "celebrate", "win", "birthday", "new years", "wedding"],
+ "moji": "🎊"
+ },
+ "confounded": {
+ "unicode": "1F616",
+ "unicode_alternates": [],
+ "name": "confounded face",
+ "shortname": ":confounded:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["confused", "face", "sick", "unwell", "confound", "amaze", "perplex", "puzzle", "mystify"],
+ "moji": "😖"
+ },
+ "confused": {
+ "unicode": "1F615",
+ "unicode_alternates": [],
+ "name": "confused face",
+ "shortname": ":confused:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [">:\\", ">:/", ":-/", ":-.", ":/", ":\\", "=/", "=\\", ":L", "=L"],
+ "keywords": ["confused", "confuse", "daze", "perplex", "puzzle", "indifference", "skeptical", "undecided", "uneasy", "hesitant"],
+ "moji": "😕"
+ },
+ "congratulations": {
+ "unicode": "3297",
+ "unicode_alternates": ["3297-FE0F"],
+ "name": "circled ideograph congratulation",
+ "shortname": ":congratulations:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "japanese", "kanji"],
+ "moji": "㊗"
+ },
+ "construction": {
+ "unicode": "1F6A7",
+ "unicode_alternates": [],
+ "name": "construction sign",
+ "shortname": ":construction:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["caution", "progress", "wip"],
+ "moji": "🚧"
+ },
+ "construction_worker": {
+ "unicode": "1F477",
+ "unicode_alternates": [],
+ "name": "construction worker",
+ "shortname": ":construction_worker:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["human", "male", "man", "wip"],
+ "moji": "👷"
+ },
+ "control_knobs": {
+ "unicode": "1F39B",
+ "unicode_alternates": [],
+ "name": "control knobs",
+ "shortname": ":control_knobs:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dial"]
+ },
+ "contruction_site": {
+ "unicode": "1F3D7",
+ "unicode_alternates": [],
+ "name": "building construction",
+ "shortname": ":contruction_site:",
+ "category": "travel_places",
+ "aliases": [":building_construction:"],
+ "aliases_ascii": [],
+ "keywords": ["site", "work"]
+ },
+ "convenience_store": {
+ "unicode": "1F3EA",
+ "unicode_alternates": [],
+ "name": "convenience store",
+ "shortname": ":convenience_store:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building"],
+ "moji": "🏪"
+ },
+ "cookie": {
+ "unicode": "1F36A",
+ "unicode_alternates": [],
+ "name": "cookie",
+ "shortname": ":cookie:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chocolate", "food", "oreo", "snack", "cookie", "dessert", "biscuit", "sweet", "chocolate"],
+ "moji": "🍪"
+ },
+ "cool": {
+ "unicode": "1F192",
+ "unicode_alternates": [],
+ "name": "squared cool",
+ "shortname": ":cool:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "words"],
+ "moji": "🆒"
+ },
+ "cop": {
+ "unicode": "1F46E",
+ "unicode_alternates": [],
+ "name": "police officer",
+ "shortname": ":cop:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrest", "enforcement", "law", "man", "police"],
+ "moji": "👮"
+ },
+ "copyright": {
+ "moji": "©",
+ "unicode": "00A9",
+ "unicode_alternates": [],
+ "name": "copyright sign",
+ "shortname": ":copyright:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ip", "license"]
+ },
+ "corn": {
+ "unicode": "1F33D",
+ "unicode_alternates": [],
+ "name": "ear of maize",
+ "shortname": ":corn:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "plant", "vegetable", "corn", "maize", "food", "iowa", "kernel", "popcorn", "husk", "yellow", "stalk", "cob", "ear"],
+ "moji": "🌽"
+ },
+ "couch": {
+ "unicode": "1F6CB",
+ "unicode_alternates": [],
+ "name": "couch and lamp",
+ "shortname": ":couch:",
+ "category": "travel_places",
+ "aliases": [":couch_and_lamp:"],
+ "aliases_ascii": [],
+ "keywords": ["lounge", "sectional", "sofa", "loveseat", "leather", "microfiber", "sit", "relax"]
+ },
+ "couple": {
+ "unicode": "1F46B",
+ "unicode_alternates": [],
+ "name": "man and woman holding hands",
+ "shortname": ":couple:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "date", "dating", "human", "like", "love", "marriage", "people", "valentines"],
+ "moji": "👫"
+ },
+ "couple_mm": {
+ "unicode": "1F468-2764-1F468",
+ "unicode_alternates": ["1F468-200D-2764-FE0F-200D-1F468"],
+ "name": "couple (man,man)",
+ "shortname": ":couple_mm:",
+ "category": "people",
+ "aliases": [":couple_with_heart_mm:"],
+ "aliases_ascii": [],
+ "keywords": ["affection", "dating", "human", "like", "love", "marriage", "valentines"]
+ },
+ "couple_with_heart": {
+ "unicode": "1F491",
+ "unicode_alternates": [],
+ "name": "couple with heart",
+ "shortname": ":couple_with_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "dating", "human", "like", "love", "marriage", "valentines"],
+ "moji": "💑"
+ },
+ "couple_ww": {
+ "unicode": "1F469-2764-1F469",
+ "unicode_alternates": ["1F469-200D-2764-FE0F-200D-1F469"],
+ "name": "couple (woman,woman)",
+ "shortname": ":couple_ww:",
+ "category": "people",
+ "aliases": [":couple_with_heart_ww:"],
+ "aliases_ascii": [],
+ "keywords": ["affection", "dating", "human", "like", "love", "marriage", "valentines"]
+ },
+ "couplekiss": {
+ "unicode": "1F48F",
+ "unicode_alternates": [],
+ "name": "kiss",
+ "shortname": ":couplekiss:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dating", "like", "love", "marriage", "valentines"],
+ "moji": "💏"
+ },
+ "cow": {
+ "unicode": "1F42E",
+ "unicode_alternates": [],
+ "name": "cow face",
+ "shortname": ":cow:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "beef", "ox"],
+ "moji": "🐮"
+ },
+ "cow2": {
+ "unicode": "1F404",
+ "unicode_alternates": [],
+ "name": "cow",
+ "shortname": ":cow2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "beef", "nature", "ox", "cow", "milk", "dairy", "beef", "bessie", "moo"],
+ "moji": "🐄"
+ },
+ "crayon": {
+ "unicode": "1F58D",
+ "unicode_alternates": [],
+ "name": "lower left crayon",
+ "shortname": ":crayon:",
+ "category": "objects_symbols",
+ "aliases": [":lower_left_crayon:"],
+ "aliases_ascii": [],
+ "keywords": ["write", "draw", "color", "wax"]
+ },
+ "credit_card": {
+ "unicode": "1F4B3",
+ "unicode_alternates": [],
+ "name": "credit card",
+ "shortname": ":credit_card:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bill", "dollar", "money", "pay", "payment", "credit", "card", "loan", "purchase", "shopping", "mastercard", "visa", "american express", "wallet", "signature"],
+ "moji": "💳"
+ },
+ "crescent_moon": {
+ "unicode": "1F319",
+ "unicode_alternates": [],
+ "name": "crescent moon",
+ "shortname": ":crescent_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "moon", "crescent", "waxing", "sky", "night", "cheese", "phase"],
+ "moji": "🌙"
+ },
+ "crocodile": {
+ "unicode": "1F40A",
+ "unicode_alternates": [],
+ "name": "crocodile",
+ "shortname": ":crocodile:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "crocodile", "croc", "alligator", "gator", "cranky"],
+ "moji": "🐊"
+ },
+ "cross_heavy": {
+ "unicode": "1F547",
+ "unicode_alternates": [],
+ "name": "heavy latin cross",
+ "shortname": ":cross_heavy:",
+ "category": "objects_symbols",
+ "aliases": [":heavy_latin_cross:"],
+ "aliases_ascii": [],
+ "keywords": ["religion", "symbol"]
+ },
+ "cross_white": {
+ "unicode": "1F546",
+ "unicode_alternates": [],
+ "name": "white latin cross",
+ "shortname": ":cross_white:",
+ "category": "objects_symbols",
+ "aliases": [":white_latin_cross:"],
+ "aliases_ascii": [],
+ "keywords": ["religion", "symbol"]
+ },
+ "crossbones": {
+ "unicode": "1F571",
+ "unicode_alternates": [],
+ "name": "black skull and crossbones",
+ "shortname": ":crossbones:",
+ "category": "objects_symbols",
+ "aliases": [":black_skull_and_crossbones:"],
+ "aliases_ascii": [],
+ "keywords": ["poison", "danger", "death"]
+ },
+ "crossed_flags": {
+ "unicode": "1F38C",
+ "unicode_alternates": [],
+ "name": "crossed flags",
+ "shortname": ":crossed_flags:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japan"],
+ "moji": "🎌"
+ },
+ "crown": {
+ "unicode": "1F451",
+ "unicode_alternates": [],
+ "name": "crown",
+ "shortname": ":crown:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["king", "kod", "leader", "royalty"],
+ "moji": "👑"
+ },
+ "cruise_ship": {
+ "unicode": "1F6F3",
+ "unicode_alternates": [],
+ "name": "passenger ship",
+ "shortname": ":cruise_ship:",
+ "category": "travel_places",
+ "aliases": [":passenger_ship:"],
+ "aliases_ascii": [],
+ "keywords": ["titanic", "transportation", "boat"]
+ },
+ "cry": {
+ "unicode": "1F622",
+ "unicode_alternates": [],
+ "name": "crying face",
+ "shortname": ":cry:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":'(", ":'-(", ";(", ";-("],
+ "keywords": ["face", "sad", "sad", "cry", "tear", "weep", "tears"],
+ "moji": "😢"
+ },
+ "crying_cat_face": {
+ "unicode": "1F63F",
+ "unicode_alternates": [],
+ "name": "crying cat face",
+ "shortname": ":crying_cat_face:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "sad", "tears", "weep", "cry", "cat", "sob", "tears", "sad", "melancholy", "morn", "somber", "hurt"],
+ "moji": "😿"
+ },
+ "crystal_ball": {
+ "unicode": "1F52E",
+ "unicode_alternates": [],
+ "name": "crystal ball",
+ "shortname": ":crystal_ball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["disco", "party"],
+ "moji": "🔮"
+ },
+ "cupid": {
+ "unicode": "1F498",
+ "unicode_alternates": [],
+ "name": "heart with arrow",
+ "shortname": ":cupid:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "heart", "like", "love", "valentines"],
+ "moji": "💘"
+ },
+ "curly_loop": {
+ "unicode": "27B0",
+ "unicode_alternates": [],
+ "name": "curly loop",
+ "shortname": ":curly_loop:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["scribble"],
+ "moji": "➰"
+ },
+ "currency_exchange": {
+ "unicode": "1F4B1",
+ "unicode_alternates": [],
+ "name": "currency exchange",
+ "shortname": ":currency_exchange:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dollar", "money", "travel"],
+ "moji": "💱"
+ },
+ "curry": {
+ "unicode": "1F35B",
+ "unicode_alternates": [],
+ "name": "curry and rice",
+ "shortname": ":curry:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "hot", "indian", "spicy", "curry", "spice", "flavor", "food", "meal"],
+ "moji": "🍛"
+ },
+ "custard": {
+ "unicode": "1F36E",
+ "unicode_alternates": [],
+ "name": "custard",
+ "shortname": ":custard:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "custard", "cream", "rich", "butter", "dessert", "crème", "brûlée", "french"],
+ "moji": "🍮"
+ },
+ "customs": {
+ "unicode": "1F6C3",
+ "unicode_alternates": [],
+ "name": "customs",
+ "shortname": ":customs:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["border", "passport", "customs", "travel", "foreign", "goods", "check", "authority", "government"],
+ "moji": "🛃"
+ },
+ "cyclone": {
+ "moji": "🌀",
+ "unicode": "1F300",
+ "unicode_alternates": [],
+ "name": "cyclone",
+ "shortname": ":cyclone:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue", "cloud", "swirl", "weather", "cyclone", "hurricane", "typhoon", "storm", "ocean"]
+ },
+ "dagger": {
+ "unicode": "1F5E1",
+ "unicode_alternates": [],
+ "name": "dagger knife",
+ "shortname": ":dagger:",
+ "category": "objects_symbols",
+ "aliases": [":dagger_knife:"],
+ "aliases_ascii": [],
+ "keywords": ["blade", "knife"]
+ },
+ "dancer": {
+ "unicode": "1F483",
+ "unicode_alternates": [],
+ "name": "dancer",
+ "shortname": ":dancer:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "fun", "girl", "woman", "dance", "dancer", "dress", "fancy", "boogy", "party", "celebrate", "ballet", "tango", "cha cha", "music"],
+ "moji": "💃"
+ },
+ "dancers": {
+ "unicode": "1F46F",
+ "unicode_alternates": [],
+ "name": "woman with bunny ears",
+ "shortname": ":dancers:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bunny", "female", "girls", "women", "dancing", "dancers", "showgirl", "playboy", "costume", "bunny", "cancan"],
+ "moji": "👯"
+ },
+ "dango": {
+ "unicode": "1F361",
+ "unicode_alternates": [],
+ "name": "dango",
+ "shortname": ":dango:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "dango", "japanese", "dumpling", "mochi", "balls", "skewer"],
+ "moji": "🍡"
+ },
+ "dark_sunglasses": {
+ "unicode": "1F576",
+ "unicode_alternates": [],
+ "name": "dark sunglasses",
+ "shortname": ":dark_sunglasses:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shades", "eyes"]
+ },
+ "dart": {
+ "unicode": "1F3AF",
+ "unicode_alternates": [],
+ "name": "direct hit",
+ "shortname": ":dart:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bar", "game", "direct", "hit", "bullseye", "dart", "archery", "game", "fletching", "arrow", "sport"],
+ "moji": "🎯"
+ },
+ "dash": {
+ "unicode": "1F4A8",
+ "unicode_alternates": [],
+ "name": "dash symbol",
+ "shortname": ":dash:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["air", "fast", "shoo", "wind"],
+ "moji": "💨"
+ },
+ "date": {
+ "unicode": "1F4C5",
+ "unicode_alternates": [],
+ "name": "calendar",
+ "shortname": ":date:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["calendar", "schedule"],
+ "moji": "📅"
+ },
+ "deciduous_tree": {
+ "unicode": "1F333",
+ "unicode_alternates": [],
+ "name": "deciduous tree",
+ "shortname": ":deciduous_tree:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "deciduous", "tree", "leaves", "fall", "color"],
+ "moji": "🌳"
+ },
+ "department_store": {
+ "unicode": "1F3EC",
+ "unicode_alternates": [],
+ "name": "department store",
+ "shortname": ":department_store:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "mall", "shopping", "department", "store", "retail", "sale", "merchandise"],
+ "moji": "🏬"
+ },
+ "descending_notes": {
+ "unicode": "1F39D",
+ "unicode_alternates": [],
+ "name": "beamed descending musical notes",
+ "shortname": ":descending_notes:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["score", "music", "sound", "tone"]
+ },
+ "desert": {
+ "unicode": "1F3DC",
+ "unicode_alternates": [],
+ "name": "desert",
+ "shortname": ":desert:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hot", "dry", "sandy", "cactus", "sunny", "barren"]
+ },
+ "desktop": {
+ "unicode": "1F5A5",
+ "unicode_alternates": [],
+ "name": "desktop computer",
+ "shortname": ":desktop:",
+ "category": "objects_symbols",
+ "aliases": [":desktop_computer:"],
+ "aliases_ascii": [],
+ "keywords": ["cpu"]
+ },
+ "desktop_window": {
+ "unicode": "1F5D4",
+ "unicode_alternates": [],
+ "name": "desktop window",
+ "shortname": ":desktop_window:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["computer"]
+ },
+ "diamond_shape_with_a_dot_inside": {
+ "unicode": "1F4A0",
+ "unicode_alternates": [],
+ "name": "diamond shape with a dot inside",
+ "shortname": ":diamond_shape_with_a_dot_inside:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["diamond", "cute", "cuteness", "kawaii", "japanese", "glyph", "adorable"],
+ "moji": "💠"
+ },
+ "diamonds": {
+ "unicode": "2666",
+ "unicode_alternates": ["2666-FE0F"],
+ "name": "black diamond suit",
+ "shortname": ":diamonds:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cards", "poker"],
+ "moji": "♦"
+ },
+ "disappointed": {
+ "unicode": "1F61E",
+ "unicode_alternates": [],
+ "name": "disappointed face",
+ "shortname": ":disappointed:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [">:[", ":-(", ":(", ":-[", ":[", "=("],
+ "keywords": ["disappointed", "disappoint", "frown", "depressed", "discouraged", "face", "sad", "upset"],
+ "moji": "😞"
+ },
+ "disappointed_relieved": {
+ "unicode": "1F625",
+ "unicode_alternates": [],
+ "name": "disappointed but relieved face",
+ "shortname": ":disappointed_relieved:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "nervous", "phew", "sweat", "disappoint", "relief"],
+ "moji": "😥"
+ },
+ "dividers": {
+ "unicode": "1F5C2",
+ "unicode_alternates": [],
+ "name": "card index dividers",
+ "shortname": ":dividers:",
+ "category": "objects_symbols",
+ "aliases": [":card_index_dividers:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery", "rolodex"]
+ },
+ "dizzy": {
+ "unicode": "1F4AB",
+ "unicode_alternates": [],
+ "name": "dizzy symbol",
+ "shortname": ":dizzy:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shoot", "sparkle", "star", "dizzy", "drunk", "sick", "intoxicated", "squeans", "starburst", "star"],
+ "moji": "💫"
+ },
+ "dizzy_face": {
+ "unicode": "1F635",
+ "unicode_alternates": [],
+ "name": "dizzy face",
+ "shortname": ":dizzy_face:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["#-)", "#)", "%-)", "%)", "X)", "X-)"],
+ "keywords": ["dizzy", "drunk", "inebriated", "face", "spent", "unconscious", "xox"],
+ "moji": "😵"
+ },
+ "do_not_litter": {
+ "unicode": "1F6AF",
+ "unicode_alternates": [],
+ "name": "do not litter symbol",
+ "shortname": ":do_not_litter:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bin", "garbage", "trash", "litter", "garbage", "waste", "no", "can", "trash"],
+ "moji": "🚯"
+ },
+ "document": {
+ "unicode": "1F5CE",
+ "unicode_alternates": [],
+ "name": "document",
+ "shortname": ":document:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["page"]
+ },
+ "document_text": {
+ "unicode": "1F5B9",
+ "unicode_alternates": [],
+ "name": "document with text",
+ "shortname": ":document_text:",
+ "category": "objects_symbols",
+ "aliases": [":document_with_text:"],
+ "aliases_ascii": [],
+ "keywords": ["page"]
+ },
+ "dog": {
+ "unicode": "1F436",
+ "unicode_alternates": [],
+ "name": "dog face",
+ "shortname": ":dog:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "friend", "nature", "woof"],
+ "moji": "🐶"
+ },
+ "dog2": {
+ "unicode": "1F415",
+ "unicode_alternates": [],
+ "name": "dog",
+ "shortname": ":dog2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "doge", "friend", "nature", "pet", "dog", "puppy", "pet", "friend", "woof", "bark", "fido"],
+ "moji": "🐕"
+ },
+ "dollar": {
+ "unicode": "1F4B5",
+ "unicode_alternates": [],
+ "name": "banknote with dollar sign",
+ "shortname": ":dollar:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bill", "currency", "money", "dollar", "united states", "canada", "australia", "banknote", "money", "currency", "paper", "cash", "bills"],
+ "moji": "💵"
+ },
+ "dolls": {
+ "unicode": "1F38E",
+ "unicode_alternates": [],
+ "name": "japanese dolls",
+ "shortname": ":dolls:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japanese", "kimono", "toy", "dolls", "japan", "japanese", "day", "girls", "emperor", "empress", "pray", "blessing", "imperial", "family", "royal"],
+ "moji": "🎎"
+ },
+ "dolphin": {
+ "unicode": "1F42C",
+ "unicode_alternates": [],
+ "name": "dolphin",
+ "shortname": ":dolphin:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "fins", "fish", "flipper", "nature", "ocean", "sea"],
+ "moji": "🐬"
+ },
+ "door": {
+ "unicode": "1F6AA",
+ "unicode_alternates": [],
+ "name": "door",
+ "shortname": ":door:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["entry", "exit", "house", "door", "doorway", "entrance", "enter", "exit", "entry"],
+ "moji": "🚪"
+ },
+ "doughnut": {
+ "unicode": "1F369",
+ "unicode_alternates": [],
+ "name": "doughnut",
+ "shortname": ":doughnut:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "snack", "sweet", "doughnut", "donut", "pastry", "fried", "dessert", "breakfast", "police", "homer", "sweet"],
+ "moji": "🍩"
+ },
+ "dove": {
+ "unicode": "1F54A",
+ "unicode_alternates": [],
+ "name": "dove of peace",
+ "shortname": ":dove:",
+ "category": "objects_symbols",
+ "aliases": [":dove_of_peace:"],
+ "aliases_ascii": [],
+ "keywords": ["symbol", "bird"]
+ },
+ "dragon": {
+ "unicode": "1F409",
+ "unicode_alternates": [],
+ "name": "dragon",
+ "shortname": ":dragon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "chinese", "green", "myth", "nature", "dragon", "fire", "legendary", "myth"],
+ "moji": "🐉"
+ },
+ "dragon_face": {
+ "unicode": "1F432",
+ "unicode_alternates": [],
+ "name": "dragon face",
+ "shortname": ":dragon_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "chinese", "green", "myth", "nature", "dragon", "head", "fire", "legendary", "myth"],
+ "moji": "🐲"
+ },
+ "dress": {
+ "unicode": "1F457",
+ "unicode_alternates": [],
+ "name": "dress",
+ "shortname": ":dress:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clothes", "fashion"],
+ "moji": "👗"
+ },
+ "dromedary_camel": {
+ "unicode": "1F42A",
+ "unicode_alternates": [],
+ "name": "dromedary camel",
+ "shortname": ":dromedary_camel:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "desert", "hot", "dromedary", "camel", "hump", "desert", "middle east", "heat", "hot", "water", "hump day", "wednesday", "sex"],
+ "moji": "🐪"
+ },
+ "droplet": {
+ "unicode": "1F4A7",
+ "unicode_alternates": [],
+ "name": "droplet",
+ "shortname": ":droplet:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["drip", "faucet", "water", "drop", "droplet", "h20", "water", "aqua", "tear", "sweat", "rain", "moisture", "wet", "moist", "spit"],
+ "moji": "💧"
+ },
+ "dvd": {
+ "unicode": "1F4C0",
+ "unicode_alternates": [],
+ "name": "dvd",
+ "shortname": ":dvd:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cd", "disc", "disk"],
+ "moji": "📀"
+ },
+ "e-mail": {
+ "unicode": "1F4E7",
+ "unicode_alternates": [],
+ "name": "e-mail symbol",
+ "shortname": ":e-mail:",
+ "category": "objects",
+ "aliases": [":email:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "inbox"],
+ "moji": "📧"
+ },
+ "ear": {
+ "unicode": "1F442",
+ "unicode_alternates": [],
+ "name": "ear",
+ "shortname": ":ear:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "hear", "listen", "sound"],
+ "moji": "👂"
+ },
+ "ear_of_rice": {
+ "unicode": "1F33E",
+ "unicode_alternates": [],
+ "name": "ear of rice",
+ "shortname": ":ear_of_rice:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "ear", "rice", "food", "plant", "seed"],
+ "moji": "🌾"
+ },
+ "earth_africa": {
+ "unicode": "1F30D",
+ "unicode_alternates": [],
+ "name": "earth globe europe-africa",
+ "shortname": ":earth_africa:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["globe", "international", "world", "earth", "globe", "space", "planet", "africa", "europe", "home"],
+ "moji": "🌍"
+ },
+ "earth_americas": {
+ "unicode": "1F30E",
+ "unicode_alternates": [],
+ "name": "earth globe americas",
+ "shortname": ":earth_americas:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["USA", "globe", "international", "world", "earth", "globe", "space", "planet", "north", "south", "america", "americas", "home"],
+ "moji": "🌎"
+ },
+ "earth_asia": {
+ "unicode": "1F30F",
+ "unicode_alternates": [],
+ "name": "earth globe asia-australia",
+ "shortname": ":earth_asia:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["east", "globe", "international", "world", "earth", "globe", "space", "planet", "asia", "australia", "home"],
+ "moji": "🌏"
+ },
+ "egg": {
+ "unicode": "1F373",
+ "unicode_alternates": [],
+ "name": "cooking",
+ "shortname": ":egg:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["breakfast", "food", "egg", "fry", "pan", "flat", "cook", "frying", "cooking", "utensil"],
+ "moji": "🍳"
+ },
+ "eggplant": {
+ "unicode": "1F346",
+ "unicode_alternates": [],
+ "name": "aubergine",
+ "shortname": ":eggplant:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["aubergine", "food", "nature", "vegetable", "eggplant", "aubergine", "fruit", "purple", "penis"],
+ "moji": "🍆"
+ },
+ "eight": {
+ "moji": "8️⃣",
+ "unicode": "0038-20E3",
+ "unicode_alternates": ["0038-FE0F-20E3"],
+ "name": "digit eight",
+ "shortname": ":eight:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["8", "blue-square", "numbers"]
+ },
+ "eight_pointed_black_star": {
+ "unicode": "2734",
+ "unicode_alternates": ["2734-FE0F"],
+ "name": "eight pointed black star",
+ "shortname": ":eight_pointed_black_star:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "✴"
+ },
+ "eight_spoked_asterisk": {
+ "unicode": "2733",
+ "unicode_alternates": ["2733-FE0F"],
+ "name": "eight spoked asterisk",
+ "shortname": ":eight_spoked_asterisk:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["green-square", "sparkle", "star"],
+ "moji": "✳"
+ },
+ "electric_plug": {
+ "unicode": "1F50C",
+ "unicode_alternates": [],
+ "name": "electric plug",
+ "shortname": ":electric_plug:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["charger", "power"],
+ "moji": "🔌"
+ },
+ "elephant": {
+ "unicode": "1F418",
+ "unicode_alternates": [],
+ "name": "elephant",
+ "shortname": ":elephant:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "nose", "thailand"],
+ "moji": "🐘"
+ },
+ "end": {
+ "unicode": "1F51A",
+ "unicode_alternates": [],
+ "name": "end with leftwards arrow above",
+ "shortname": ":end:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "words"],
+ "moji": "🔚"
+ },
+ "envelope": {
+ "unicode": "2709",
+ "unicode_alternates": ["2709-FE0F"],
+ "name": "envelope",
+ "shortname": ":envelope:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "letter", "mail", "postal"],
+ "moji": "✉"
+ },
+ "envelope_back": {
+ "unicode": "1F582",
+ "unicode_alternates": [],
+ "name": "back of envelope",
+ "shortname": ":envelope_back:",
+ "category": "objects_symbols",
+ "aliases": [":back_of_envelope:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "letter", "mail", "postal"]
+ },
+ "envelope_flying": {
+ "unicode": "1F585",
+ "unicode_alternates": [],
+ "name": "flying envelope",
+ "shortname": ":envelope_flying:",
+ "category": "objects_symbols",
+ "aliases": [":flying_envelope:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "letter", "mail", "postal"]
+ },
+ "envelope_stamped": {
+ "unicode": "1F583",
+ "unicode_alternates": [],
+ "name": "stamped envelope",
+ "shortname": ":envelope_stamped:",
+ "category": "objects_symbols",
+ "aliases": [":stamped_envelope:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "letter", "mail", "postal"]
+ },
+ "envelope_stamped_pen": {
+ "unicode": "1F586",
+ "unicode_alternates": [],
+ "name": "pen over stamped envelope",
+ "shortname": ":envelope_stamped_pen:",
+ "category": "objects_symbols",
+ "aliases": [":pen_over_stamped_envelope:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "letter", "mail", "postal"]
+ },
+ "envelope_with_arrow": {
+ "unicode": "1F4E9",
+ "unicode_alternates": [],
+ "name": "envelope with downwards arrow above",
+ "shortname": ":envelope_with_arrow:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["email"],
+ "moji": "📩"
+ },
+ "euro": {
+ "unicode": "1F4B6",
+ "unicode_alternates": [],
+ "name": "banknote with euro sign",
+ "shortname": ":euro:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["currency", "dollar", "money", "euro", "europe", "banknote", "money", "currency", "paper", "cash", "bills"],
+ "moji": "💶"
+ },
+ "european_castle": {
+ "unicode": "1F3F0",
+ "unicode_alternates": [],
+ "name": "european castle",
+ "shortname": ":european_castle:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "history", "royalty", "castle", "european", "residence", "royalty", "disneyland", "disney", "fort", "fortified", "moat", "tower", "princess", "prince", "lord", "king", "queen", "fortress", "nobel", "stronghold"],
+ "moji": "🏰"
+ },
+ "european_post_office": {
+ "unicode": "1F3E4",
+ "unicode_alternates": [],
+ "name": "european post office",
+ "shortname": ":european_post_office:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building"],
+ "moji": "🏤"
+ },
+ "evergreen_tree": {
+ "unicode": "1F332",
+ "unicode_alternates": [],
+ "name": "evergreen tree",
+ "shortname": ":evergreen_tree:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "evergreen", "tree", "needles", "christmas"],
+ "moji": "🌲"
+ },
+ "exclamation": {
+ "unicode": "2757",
+ "unicode_alternates": ["2757-FE0F"],
+ "name": "heavy exclamation mark symbol",
+ "shortname": ":exclamation:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["surprise"],
+ "moji": "❗"
+ },
+ "expressionless": {
+ "unicode": "1F611",
+ "unicode_alternates": [],
+ "name": "expressionless face",
+ "shortname": ":expressionless:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["-_-", "-__-", "-___-"],
+ "keywords": ["expressionless", "blank", "void", "vapid", "without expression", "face", "indifferent"],
+ "moji": "😑"
+ },
+ "eye": {
+ "unicode": "1F441",
+ "unicode_alternates": [],
+ "name": "eye",
+ "shortname": ":eye:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["look", "peek", "watch"]
+ },
+ "eyeglasses": {
+ "unicode": "1F453",
+ "unicode_alternates": [],
+ "name": "eyeglasses",
+ "shortname": ":eyeglasses:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "eyesight", "fashion", "eyeglasses", "spectacles", "eye", "sight", "nearsightedness", "myopia", "farsightedness", "hyperopia", "frames", "vision", "see", "blurry", "contacts"],
+ "moji": "👓"
+ },
+ "eyes": {
+ "unicode": "1F440",
+ "unicode_alternates": [],
+ "name": "eyes",
+ "shortname": ":eyes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["look", "peek", "stalk", "watch"],
+ "moji": "👀"
+ },
+ "factory": {
+ "unicode": "1F3ED",
+ "unicode_alternates": [],
+ "name": "factory",
+ "shortname": ":factory:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building"],
+ "moji": "🏭"
+ },
+ "fallen_leaf": {
+ "unicode": "1F342",
+ "unicode_alternates": [],
+ "name": "fallen leaf",
+ "shortname": ":fallen_leaf:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["leaves", "nature", "plant", "vegetable", "leaf", "fall", "color", "deciduous", "autumn"],
+ "moji": "🍂"
+ },
+ "family": {
+ "unicode": "1F46A",
+ "unicode_alternates": [],
+ "name": "family",
+ "shortname": ":family:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["child", "dad", "father", "home", "mom", "mother", "parents", "family", "mother", "father", "child", "girl", "boy", "group", "unit"],
+ "moji": "👪"
+ },
+ "family_mmb": {
+ "unicode": "1F468-1F468-1F466",
+ "unicode_alternates": ["1F468-200D-1F468-200D-1F466"],
+ "name": "family (man,man,boy)",
+ "shortname": ":family_mmb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["child", "dad", "father", "parents", "group", "unit", "gay", "homosexual", "man", "boy"]
+ },
+ "family_mmbb": {
+ "unicode": "1F468-1F468-1F466-1F466",
+ "unicode_alternates": ["1F468-200D-1F468-200D-1F466-200D-1F466"],
+ "name": "family (man,man,boy,boy)",
+ "shortname": ":family_mmbb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["children", "dad", "father", "parents", "group", "unit", "gay", "homosexual", "man", "boy"]
+ },
+ "family_mmg": {
+ "unicode": "1F468-1F468-1F467",
+ "unicode_alternates": ["1F468-200D-1F468-200D-1F467"],
+ "name": "family (man,man,girl)",
+ "shortname": ":family_mmg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["child", "dad", "father", "parents", "group", "unit", "gay", "homosexual", "man", "girl"]
+ },
+ "family_mmgb": {
+ "unicode": "1F468-1F468-1F467-1F466",
+ "unicode_alternates": ["1F468-200D-1F468-200D-1F467-200D-1F466"],
+ "name": "family (man,man,girl,boy)",
+ "shortname": ":family_mmgb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["children", "dad", "father", "parents", "group", "unit", "gay", "homosexual", "man", "girl", "boy"]
+ },
+ "family_mmgg": {
+ "unicode": "1F468-1F468-1F467-1F467",
+ "unicode_alternates": ["1F468-200D-1F468-200D-1F467-200D-1F467"],
+ "name": "family (man,man,girl,girl)",
+ "shortname": ":family_mmgg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["children", "dad", "father", "parents", "group", "unit", "gay", "homosexual", "man", "girl"]
+ },
+ "family_mwbb": {
+ "unicode": "1F468-1F469-1F466-1F466",
+ "unicode_alternates": ["1F468-200D-1F469-200D-1F466-200D-1F466"],
+ "name": "family (man,woman,boy,boy)",
+ "shortname": ":family_mwbb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dad", "father", "mom", "mother", "parents", "children", "boy", "group", "unit", "man", "woman"]
+ },
+ "family_mwg": {
+ "unicode": "1F468-1F469-1F467",
+ "unicode_alternates": ["1F468-200D-1F469-200D-1F467"],
+ "name": "family (man,woman,girl)",
+ "shortname": ":family_mwg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["child", "dad", "father", "mom", "mother", "parents", "girl", "boy", "group", "unit", "man", "woman"]
+ },
+ "family_mwgb": {
+ "unicode": "1F468-1F469-1F467-1F466",
+ "unicode_alternates": ["1F468-200D-1F469-200D-1F467-200D-1F466"],
+ "name": "family (man,woman,girl,boy)",
+ "shortname": ":family_mwgb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dad", "father", "mom", "mother", "parents", "children", "girl", "boy", "group", "unit", "man", "woman"]
+ },
+ "family_mwgg": {
+ "unicode": "1F468-1F469-1F467-1F467",
+ "unicode_alternates": ["1F468-200D-1F469-200D-1F467-200D-1F467"],
+ "name": "family (man,woman,girl,girl)",
+ "shortname": ":family_mwgg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dad", "father", "mom", "mother", "parents", "children", "girl", "group", "unit", "man", "woman"]
+ },
+ "family_wwb": {
+ "unicode": "1F469-1F469-1F466",
+ "unicode_alternates": ["1F469-200D-1F469-200D-1F466"],
+ "name": "family (woman,woman,boy)",
+ "shortname": ":family_wwb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mom", "mother", "parents", "child", "boy", "group", "unit", "gay", "lesbian", "homosexual", "woman"]
+ },
+ "family_wwbb": {
+ "unicode": "1F469-1F469-1F466-1F466",
+ "unicode_alternates": ["1F469-200D-1F469-200D-1F466-200D-1F466"],
+ "name": "family (woman,woman,boy,boy)",
+ "shortname": ":family_wwbb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mom", "mother", "parents", "children", "group", "unit", "gay", "lesbian", "homosexual", "woman", "boy"]
+ },
+ "family_wwg": {
+ "unicode": "1F469-1F469-1F467",
+ "unicode_alternates": ["1F469-200D-1F469-200D-1F467"],
+ "name": "family (woman,woman,girl)",
+ "shortname": ":family_wwg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mom", "mother", "parents", "child", "woman", "girl", "group", "unit", "gay", "lesbian", "homosexual"]
+ },
+ "family_wwgb": {
+ "unicode": "1F469-1F469-1F467-1F466",
+ "unicode_alternates": ["1F469-200D-1F469-200D-1F467-200D-1F466"],
+ "name": "family (woman,woman,girl,boy)",
+ "shortname": ":family_wwgb:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mom", "mother", "parents", "children", "group", "unit", "gay", "lesbian", "homosexual", "woman", "girl", "boy"]
+ },
+ "family_wwgg": {
+ "unicode": "1F469-1F469-1F467-1F467",
+ "unicode_alternates": ["1F469-200D-1F469-200D-1F467-200D-1F467"],
+ "name": "family (woman,woman,girl,girl)",
+ "shortname": ":family_wwgg:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mom", "mother", "parents", "children", "group", "unit", "gay", "lesbian", "homosexual", "woman", "girl"]
+ },
+ "fast_forward": {
+ "unicode": "23E9",
+ "unicode_alternates": [],
+ "name": "black right-pointing double triangle",
+ "shortname": ":fast_forward:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "⏩"
+ },
+ "fax": {
+ "unicode": "1F4E0",
+ "unicode_alternates": [],
+ "name": "fax machine",
+ "shortname": ":fax:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "technology"],
+ "moji": "📠"
+ },
+ "fearful": {
+ "unicode": "1F628",
+ "unicode_alternates": [],
+ "name": "fearful face",
+ "shortname": ":fearful:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "nervous", "oops", "scared", "terrified", "fear", "fearful", "scared", "frightened"],
+ "moji": "😨"
+ },
+ "feet": {
+ "unicode": "1F43E",
+ "unicode_alternates": [],
+ "name": "paw prints",
+ "shortname": ":feet:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cat", "dog", "footprints", "paw", "pet", "tracking", "paw", "prints", "mark", "imprints", "footsteps", "animal", "lion", "bear", "dog", "cat", "raccoon", "critter", "feet", "pawsteps"],
+ "moji": "🐾"
+ },
+ "ferris_wheel": {
+ "unicode": "1F3A1",
+ "unicode_alternates": [],
+ "name": "ferris wheel",
+ "shortname": ":ferris_wheel:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["carnival", "londoneye", "photo", "farris", "wheel", "amusement", "park", "fair", "ride", "entertainment"],
+ "moji": "🎡"
+ },
+ "file_cabinet": {
+ "unicode": "1F5C4",
+ "unicode_alternates": [],
+ "name": "file cabinet",
+ "shortname": ":file_cabinet:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["folders", "office", "documents", "storage"]
+ },
+ "file_folder": {
+ "unicode": "1F4C1",
+ "unicode_alternates": [],
+ "name": "file folder",
+ "shortname": ":file_folder:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"],
+ "moji": "📁"
+ },
+ "film_frames": {
+ "unicode": "1F39E",
+ "unicode_alternates": [],
+ "name": "film frames",
+ "shortname": ":film_frames:",
+ "category": "activity",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["movie", "record", "8mm", "16mm", "reel", "celluloid"]
+ },
+ "finger_pointing_down": {
+ "unicode": "1F597",
+ "unicode_alternates": [],
+ "name": "white down pointing left hand index",
+ "shortname": ":finger_pointing_down:",
+ "category": "people",
+ "aliases": [":white_down_pointing_left_hand_index:"],
+ "aliases_ascii": [],
+ "keywords": ["direction", "finger", "hand"]
+ },
+ "finger_pointing_down2": {
+ "unicode": "1F59F",
+ "unicode_alternates": [],
+ "name": "sideways white down pointing index",
+ "shortname": ":finger_pointing_down2:",
+ "category": "people",
+ "aliases": [":sideways_white_down_pointing_index:"],
+ "aliases_ascii": [],
+ "keywords": ["direction", "finger", "hand"]
+ },
+ "finger_pointing_left": {
+ "unicode": "1F598",
+ "unicode_alternates": [],
+ "name": "sideways white left pointing index",
+ "shortname": ":finger_pointing_left:",
+ "category": "people",
+ "aliases": [":sideways_white_left_pointing_index:"],
+ "aliases_ascii": [],
+ "keywords": ["direction", "finger", "hand"]
+ },
+ "finger_pointing_right": {
+ "unicode": "1F599",
+ "unicode_alternates": [],
+ "name": "sideways white right pointing index",
+ "shortname": ":finger_pointing_right:",
+ "category": "people",
+ "aliases": [":sideways_white_right_pointing_index:"],
+ "aliases_ascii": [],
+ "keywords": ["direction", "finger", "hand"]
+ },
+ "finger_pointing_up": {
+ "unicode": "1F59E",
+ "unicode_alternates": [],
+ "name": "sideways white up pointing index",
+ "shortname": ":finger_pointing_up:",
+ "category": "people",
+ "aliases": [":sideways_white_up_pointing_index:"],
+ "aliases_ascii": [],
+ "keywords": ["direction", "finger", "hand"]
+ },
+ "fire": {
+ "unicode": "1F525",
+ "unicode_alternates": [],
+ "name": "fire",
+ "shortname": ":fire:",
+ "category": "emoticons",
+ "aliases": [":flame:"],
+ "aliases_ascii": [],
+ "keywords": ["cook", "hot", "flame"],
+ "moji": "🔥"
+ },
+ "fire_engine": {
+ "unicode": "1F692",
+ "unicode_alternates": [],
+ "name": "fire engine",
+ "shortname": ":fire_engine:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "transportation", "vehicle", "fire", "fighter", "engine", "truck", "emergency", "medical"],
+ "moji": "🚒"
+ },
+ "fire_engine_oncoming": {
+ "unicode": "1F6F1",
+ "unicode_alternates": [],
+ "name": "oncoming fire engine",
+ "shortname": ":fire_engine_oncoming:",
+ "category": "travel_places",
+ "aliases": [":oncoming_fire_engine:"],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "fighter", "truck", "emergency"]
+ },
+ "fireworks": {
+ "unicode": "1F386",
+ "unicode_alternates": [],
+ "name": "fireworks",
+ "shortname": ":fireworks:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["carnival", "congratulations", "festival", "photo", "fireworks", "independence", "celebration", "explosion", "july", "4th", "rocket", "sky", "idea", "excitement"],
+ "moji": "🎆"
+ },
+ "first_quarter_moon": {
+ "unicode": "1F313",
+ "unicode_alternates": [],
+ "name": "first quarter moon symbol",
+ "shortname": ":first_quarter_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "quarter", "first", "sky", "night", "cheese", "phase"],
+ "moji": "🌓"
+ },
+ "first_quarter_moon_with_face": {
+ "unicode": "1F31B",
+ "unicode_alternates": [],
+ "name": "first quarter moon with face",
+ "shortname": ":first_quarter_moon_with_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "first", "quarter", "anthropomorphic", "face", "sky", "night", "cheese", "phase"],
+ "moji": "🌛"
+ },
+ "fish": {
+ "unicode": "1F41F",
+ "unicode_alternates": [],
+ "name": "fish",
+ "shortname": ":fish:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "food", "nature"],
+ "moji": "🐟"
+ },
+ "fish_cake": {
+ "unicode": "1F365",
+ "unicode_alternates": [],
+ "name": "fish cake with swirl design",
+ "shortname": ":fish_cake:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fish", "cake", "kamboko", "swirl", "ramen", "noodles", "naruto"],
+ "moji": "🍥"
+ },
+ "fishing_pole_and_fish": {
+ "unicode": "1F3A3",
+ "unicode_alternates": [],
+ "name": "fishing pole and fish",
+ "shortname": ":fishing_pole_and_fish:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "hobby", "fish", "fishing", "pole"],
+ "moji": "🎣"
+ },
+ "fist": {
+ "unicode": "270A",
+ "unicode_alternates": [],
+ "name": "raised fist",
+ "shortname": ":fist:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fingers", "grasp", "hand"],
+ "moji": "✊"
+ },
+ "five": {
+ "moji": "5️⃣",
+ "unicode": "0035-20E3",
+ "unicode_alternates": ["0035-FE0F-20E3"],
+ "name": "digit five",
+ "shortname": ":five:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "numbers", "prime"]
+ },
+ "flag_ac": {
+ "unicode": "1F1E6-1F1E8",
+ "unicode_alternates": [],
+ "name": "ascension",
+ "shortname": ":flag_ac:",
+ "category": "flags",
+ "aliases": [":ac:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ac"]
+ },
+ "flag_ad": {
+ "unicode": "1F1E6-1F1E9",
+ "unicode_alternates": [],
+ "name": "andorra",
+ "shortname": ":flag_ad:",
+ "category": "flags",
+ "aliases": [":ad:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ad"]
+ },
+ "flag_ae": {
+ "unicode": "1F1E6-1F1EA",
+ "unicode_alternates": [],
+ "name": "the united arab emirates",
+ "shortname": ":flag_ae:",
+ "category": "flags",
+ "aliases": [":ae:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ae"]
+ },
+ "flag_af": {
+ "unicode": "1F1E6-1F1EB",
+ "unicode_alternates": [],
+ "name": "afghanistan",
+ "shortname": ":flag_af:",
+ "category": "flags",
+ "aliases": [":af:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "afghanestan", "af"]
+ },
+ "flag_ag": {
+ "unicode": "1F1E6-1F1EC",
+ "unicode_alternates": [],
+ "name": "antigua and barbuda",
+ "shortname": ":flag_ag:",
+ "category": "flags",
+ "aliases": [":ag:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ag"]
+ },
+ "flag_ai": {
+ "unicode": "1F1E6-1F1EE",
+ "unicode_alternates": [],
+ "name": "anguilla",
+ "shortname": ":flag_ai:",
+ "category": "flags",
+ "aliases": [":ai:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ai"]
+ },
+ "flag_al": {
+ "unicode": "1F1E6-1F1F1",
+ "unicode_alternates": [],
+ "name": "albania",
+ "shortname": ":flag_al:",
+ "category": "flags",
+ "aliases": [":al:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "shqiperia", "al"]
+ },
+ "flag_am": {
+ "unicode": "1F1E6-1F1F2",
+ "unicode_alternates": [],
+ "name": "armenia",
+ "shortname": ":flag_am:",
+ "category": "flags",
+ "aliases": [":am:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "hayastan", "am"]
+ },
+ "flag_ao": {
+ "unicode": "1F1E6-1F1F4",
+ "unicode_alternates": [],
+ "name": "angola",
+ "shortname": ":flag_ao:",
+ "category": "flags",
+ "aliases": [":ao:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ao"]
+ },
+ "flag_ar": {
+ "unicode": "1F1E6-1F1F7",
+ "unicode_alternates": [],
+ "name": "argentina",
+ "shortname": ":flag_ar:",
+ "category": "flags",
+ "aliases": [":ar:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ar"]
+ },
+ "flag_at": {
+ "unicode": "1F1E6-1F1F9",
+ "unicode_alternates": [],
+ "name": "austria",
+ "shortname": ":flag_at:",
+ "category": "flags",
+ "aliases": [":at:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "&ouml;sterreich", "osterreich", "at"]
+ },
+ "flag_au": {
+ "unicode": "1F1E6-1F1FA",
+ "unicode_alternates": [],
+ "name": "australia",
+ "shortname": ":flag_au:",
+ "category": "flags",
+ "aliases": [":au:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "au"]
+ },
+ "flag_aw": {
+ "unicode": "1F1E6-1F1FC",
+ "unicode_alternates": [],
+ "name": "aruba",
+ "shortname": ":flag_aw:",
+ "category": "flags",
+ "aliases": [":aw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "aw"]
+ },
+ "flag_az": {
+ "unicode": "1F1E6-1F1FF",
+ "unicode_alternates": [],
+ "name": "azerbaijan",
+ "shortname": ":flag_az:",
+ "category": "flags",
+ "aliases": [":az:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "azarbaycan", "az"]
+ },
+ "flag_ba": {
+ "unicode": "1F1E7-1F1E6",
+ "unicode_alternates": [],
+ "name": "bosnia and herzegovina",
+ "shortname": ":flag_ba:",
+ "category": "flags",
+ "aliases": [":ba:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bosna i hercegovina", "ba"]
+ },
+ "flag_bb": {
+ "unicode": "1F1E7-1F1E7",
+ "unicode_alternates": [],
+ "name": "barbados",
+ "shortname": ":flag_bb:",
+ "category": "flags",
+ "aliases": [":bb:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bb"]
+ },
+ "flag_bd": {
+ "unicode": "1F1E7-1F1E9",
+ "unicode_alternates": [],
+ "name": "bangladesh",
+ "shortname": ":flag_bd:",
+ "category": "flags",
+ "aliases": [":bd:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bd"]
+ },
+ "flag_be": {
+ "unicode": "1F1E7-1F1EA",
+ "unicode_alternates": [],
+ "name": "belgium",
+ "shortname": ":flag_be:",
+ "category": "flags",
+ "aliases": [":be:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "belgique", "belgie", "be"]
+ },
+ "flag_bf": {
+ "unicode": "1F1E7-1F1EB",
+ "unicode_alternates": [],
+ "name": "burkina faso",
+ "shortname": ":flag_bf:",
+ "category": "flags",
+ "aliases": [":bf:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bf"]
+ },
+ "flag_bg": {
+ "unicode": "1F1E7-1F1EC",
+ "unicode_alternates": [],
+ "name": "bulgaria",
+ "shortname": ":flag_bg:",
+ "category": "flags",
+ "aliases": [":bg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bg"]
+ },
+ "flag_bh": {
+ "unicode": "1F1E7-1F1ED",
+ "unicode_alternates": [],
+ "name": "bahrain",
+ "shortname": ":flag_bh:",
+ "category": "flags",
+ "aliases": [":bh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al bahrayn", "bh"]
+ },
+ "flag_bi": {
+ "unicode": "1F1E7-1F1EE",
+ "unicode_alternates": [],
+ "name": "burundi",
+ "shortname": ":flag_bi:",
+ "category": "flags",
+ "aliases": [":bi:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bi"]
+ },
+ "flag_bj": {
+ "unicode": "1F1E7-1F1EF",
+ "unicode_alternates": [],
+ "name": "benin",
+ "shortname": ":flag_bj:",
+ "category": "flags",
+ "aliases": [":bj:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bj"]
+ },
+ "flag_black": {
+ "unicode": "1F3F4",
+ "unicode_alternates": [],
+ "name": "waving black flag",
+ "shortname": ":flag_black:",
+ "category": "objects_symbols",
+ "aliases": [":waving_black_flag:"],
+ "aliases_ascii": [],
+ "keywords": ["symbol", "signal"]
+ },
+ "flag_bm": {
+ "unicode": "1F1E7-1F1F2",
+ "unicode_alternates": [],
+ "name": "bermuda",
+ "shortname": ":flag_bm:",
+ "category": "flags",
+ "aliases": [":bm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bm"]
+ },
+ "flag_bn": {
+ "unicode": "1F1E7-1F1F3",
+ "unicode_alternates": [],
+ "name": "brunei",
+ "shortname": ":flag_bn:",
+ "category": "flags",
+ "aliases": [":bn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bn"]
+ },
+ "flag_bo": {
+ "unicode": "1F1E7-1F1F4",
+ "unicode_alternates": [],
+ "name": "bolivia",
+ "shortname": ":flag_bo:",
+ "category": "flags",
+ "aliases": [":bo:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bo"]
+ },
+ "flag_br": {
+ "unicode": "1F1E7-1F1F7",
+ "unicode_alternates": [],
+ "name": "brazil",
+ "shortname": ":flag_br:",
+ "category": "flags",
+ "aliases": [":br:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "brasil", "br"]
+ },
+ "flag_bs": {
+ "unicode": "1F1E7-1F1F8",
+ "unicode_alternates": [],
+ "name": "the bahamas",
+ "shortname": ":flag_bs:",
+ "category": "flags",
+ "aliases": [":bs:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bs"]
+ },
+ "flag_bt": {
+ "unicode": "1F1E7-1F1F9",
+ "unicode_alternates": [],
+ "name": "bhutan",
+ "shortname": ":flag_bt:",
+ "category": "flags",
+ "aliases": [":bt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bt"]
+ },
+ "flag_bw": {
+ "unicode": "1F1E7-1F1FC",
+ "unicode_alternates": [],
+ "name": "botswana",
+ "shortname": ":flag_bw:",
+ "category": "flags",
+ "aliases": [":bw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bw"]
+ },
+ "flag_by": {
+ "unicode": "1F1E7-1F1FE",
+ "unicode_alternates": [],
+ "name": "belarus",
+ "shortname": ":flag_by:",
+ "category": "flags",
+ "aliases": [":by:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "byelarus", "by"]
+ },
+ "flag_bz": {
+ "unicode": "1F1E7-1F1FF",
+ "unicode_alternates": [],
+ "name": "belize",
+ "shortname": ":flag_bz:",
+ "category": "flags",
+ "aliases": [":bz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bz"]
+ },
+ "flag_ca": {
+ "unicode": "1F1E8-1F1E6",
+ "unicode_alternates": [],
+ "name": "canada",
+ "shortname": ":flag_ca:",
+ "category": "flags",
+ "aliases": [":ca:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ca"]
+ },
+ "flag_cd": {
+ "unicode": "1F1E8-1F1E9",
+ "unicode_alternates": [],
+ "name": "the democratic republic of the congo",
+ "shortname": ":flag_cd:",
+ "category": "flags",
+ "aliases": [":congo:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "r&eacute;publique d&eacute;mocratique du congo", "republique democratique du congo", "cd"]
+ },
+ "flag_cf": {
+ "unicode": "1F1E8-1F1EB",
+ "unicode_alternates": [],
+ "name": "central african republic",
+ "shortname": ":flag_cf:",
+ "category": "flags",
+ "aliases": [":cf:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cf"]
+ },
+ "flag_cg": {
+ "unicode": "1F1E8-1F1EC",
+ "unicode_alternates": [],
+ "name": "the republic of the congo",
+ "shortname": ":flag_cg:",
+ "category": "flags",
+ "aliases": [":cg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cg"]
+ },
+ "flag_ch": {
+ "unicode": "1F1E8-1F1ED",
+ "unicode_alternates": [],
+ "name": "switzerland",
+ "shortname": ":flag_ch:",
+ "category": "flags",
+ "aliases": [":ch:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "swiss"]
+ },
+ "flag_ci": {
+ "unicode": "1F1E8-1F1EE",
+ "unicode_alternates": [],
+ "name": "cote d'ivoire",
+ "shortname": ":flag_ci:",
+ "category": "flags",
+ "aliases": [":ci:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ci"]
+ },
+ "flag_cl": {
+ "unicode": "1F1E8-1F1F1",
+ "unicode_alternates": [],
+ "name": "chile",
+ "shortname": ":flag_cl:",
+ "category": "flags",
+ "aliases": [":chile:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cl"]
+ },
+ "flag_cm": {
+ "unicode": "1F1E8-1F1F2",
+ "unicode_alternates": [],
+ "name": "cameroon",
+ "shortname": ":flag_cm:",
+ "category": "flags",
+ "aliases": [":cm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cm"]
+ },
+ "flag_cn": {
+ "unicode": "1F1E8-1F1F3",
+ "unicode_alternates": [],
+ "name": "china",
+ "shortname": ":flag_cn:",
+ "category": "flags",
+ "aliases": [":cn:"],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "prc", "zhong guo", "country", "nation", "cn"]
+ },
+ "flag_co": {
+ "unicode": "1F1E8-1F1F4",
+ "unicode_alternates": [],
+ "name": "colombia",
+ "shortname": ":flag_co:",
+ "category": "flags",
+ "aliases": [":co:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "co"]
+ },
+ "flag_cr": {
+ "unicode": "1F1E8-1F1F7",
+ "unicode_alternates": [],
+ "name": "costa rica",
+ "shortname": ":flag_cr:",
+ "category": "flags",
+ "aliases": [":cr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cr"]
+ },
+ "flag_cu": {
+ "unicode": "1F1E8-1F1FA",
+ "unicode_alternates": [],
+ "name": "cuba",
+ "shortname": ":flag_cu:",
+ "category": "flags",
+ "aliases": [":cu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cu"]
+ },
+ "flag_cv": {
+ "unicode": "1F1E8-1F1FB",
+ "unicode_alternates": [],
+ "name": "cape verde",
+ "shortname": ":flag_cv:",
+ "category": "flags",
+ "aliases": [":cv:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "cabo verde", "cv"]
+ },
+ "flag_cy": {
+ "unicode": "1F1E8-1F1FE",
+ "unicode_alternates": [],
+ "name": "cyprus",
+ "shortname": ":flag_cy:",
+ "category": "flags",
+ "aliases": [":cy:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kibris", "kypros", "cy"]
+ },
+ "flag_cz": {
+ "unicode": "1F1E8-1F1FF",
+ "unicode_alternates": [],
+ "name": "the czech republic",
+ "shortname": ":flag_cz:",
+ "category": "flags",
+ "aliases": [":cz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ceska republika", "cz"]
+ },
+ "flag_de": {
+ "unicode": "1F1E9-1F1EA",
+ "unicode_alternates": [],
+ "name": "germany",
+ "shortname": ":flag_de:",
+ "category": "flags",
+ "aliases": [":de:"],
+ "aliases_ascii": [],
+ "keywords": ["german", "nation", "deutschland", "country", "de"]
+ },
+ "flag_dj": {
+ "unicode": "1F1E9-1F1EF",
+ "unicode_alternates": [],
+ "name": "djibouti",
+ "shortname": ":flag_dj:",
+ "category": "flags",
+ "aliases": [":dj:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "dj"]
+ },
+ "flag_dk": {
+ "unicode": "1F1E9-1F1F0",
+ "unicode_alternates": [],
+ "name": "denmark",
+ "shortname": ":flag_dk:",
+ "category": "flags",
+ "aliases": [":dk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "danmark", "dk"]
+ },
+ "flag_dm": {
+ "unicode": "1F1E9-1F1F2",
+ "unicode_alternates": [],
+ "name": "dominica",
+ "shortname": ":flag_dm:",
+ "category": "flags",
+ "aliases": [":dm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "dm"]
+ },
+ "flag_do": {
+ "unicode": "1F1E9-1F1F4",
+ "unicode_alternates": [],
+ "name": "the dominican republic",
+ "shortname": ":flag_do:",
+ "category": "flags",
+ "aliases": [":do:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "do"]
+ },
+ "flag_dz": {
+ "unicode": "1F1E9-1F1FF",
+ "unicode_alternates": [],
+ "name": "algeria",
+ "shortname": ":flag_dz:",
+ "category": "flags",
+ "aliases": [":dz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al jaza'ir", "al jazair", "dz"]
+ },
+ "flag_ec": {
+ "unicode": "1F1EA-1F1E8",
+ "unicode_alternates": [],
+ "name": "ecuador",
+ "shortname": ":flag_ec:",
+ "category": "flags",
+ "aliases": [":ec:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ec"]
+ },
+ "flag_ee": {
+ "unicode": "1F1EA-1F1EA",
+ "unicode_alternates": [],
+ "name": "estonia",
+ "shortname": ":flag_ee:",
+ "category": "flags",
+ "aliases": [":ee:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "eesti vabariik", "ee"]
+ },
+ "flag_eg": {
+ "unicode": "1F1EA-1F1EC",
+ "unicode_alternates": [],
+ "name": "egypt",
+ "shortname": ":flag_eg:",
+ "category": "flags",
+ "aliases": [":eg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "misr", "eg"]
+ },
+ "flag_eh": {
+ "unicode": "1F1EA-1F1ED",
+ "unicode_alternates": [],
+ "name": "western sahara",
+ "shortname": ":flag_eh:",
+ "category": "flags",
+ "aliases": [":eh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "aṣ-Ṣaḥrā’ al-gharbīyah", "sahra", "gharbiyah", "eh"]
+ },
+ "flag_er": {
+ "unicode": "1F1EA-1F1F7",
+ "unicode_alternates": [],
+ "name": "eritrea",
+ "shortname": ":flag_er:",
+ "category": "flags",
+ "aliases": [":er:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "hagere ertra", "er"]
+ },
+ "flag_es": {
+ "unicode": "1F1EA-1F1F8",
+ "unicode_alternates": [],
+ "name": "spain",
+ "shortname": ":flag_es:",
+ "category": "flags",
+ "aliases": [":es:"],
+ "aliases_ascii": [],
+ "keywords": ["nation", "espa&ntilde;a", "country", "espana", "es"]
+ },
+ "flag_et": {
+ "unicode": "1F1EA-1F1F9",
+ "unicode_alternates": [],
+ "name": "ethiopia",
+ "shortname": ":flag_et:",
+ "category": "flags",
+ "aliases": [":et:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ityop'iya", "ityopiya", "et"]
+ },
+ "flag_fi": {
+ "unicode": "1F1EB-1F1EE",
+ "unicode_alternates": [],
+ "name": "finland",
+ "shortname": ":flag_fi:",
+ "category": "flags",
+ "aliases": [":fi:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "suomen tasavalta", "fi"]
+ },
+ "flag_fj": {
+ "unicode": "1F1EB-1F1EF",
+ "unicode_alternates": [],
+ "name": "fiji",
+ "shortname": ":flag_fj:",
+ "category": "flags",
+ "aliases": [":fj:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "fj"]
+ },
+ "flag_fk": {
+ "unicode": "1F1EB-1F1F0",
+ "unicode_alternates": [],
+ "name": "falkland islands",
+ "shortname": ":flag_fk:",
+ "category": "flags",
+ "aliases": [":fk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "islas malvinas", "fk"]
+ },
+ "flag_fm": {
+ "unicode": "1F1EB-1F1F2",
+ "unicode_alternates": [],
+ "name": "micronesia",
+ "shortname": ":flag_fm:",
+ "category": "flags",
+ "aliases": [":fm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "fm"]
+ },
+ "flag_fo": {
+ "unicode": "1F1EB-1F1F4",
+ "unicode_alternates": [],
+ "name": "faroe islands",
+ "shortname": ":flag_fo:",
+ "category": "flags",
+ "aliases": [":fo:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "foroyar", "fo"]
+ },
+ "flag_fr": {
+ "unicode": "1F1EB-1F1F7",
+ "unicode_alternates": [],
+ "name": "france",
+ "shortname": ":flag_fr:",
+ "category": "flags",
+ "aliases": [":fr:"],
+ "aliases_ascii": [],
+ "keywords": ["french", "nation", "country", "fr"]
+ },
+ "flag_ga": {
+ "unicode": "1F1EC-1F1E6",
+ "unicode_alternates": [],
+ "name": "gabon",
+ "shortname": ":flag_ga:",
+ "category": "flags",
+ "aliases": [":ga:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ga"]
+ },
+ "flag_gb": {
+ "unicode": "1F1EC-1F1E7",
+ "unicode_alternates": [],
+ "name": "great britain",
+ "shortname": ":flag_gb:",
+ "category": "flags",
+ "aliases": [":gb:"],
+ "aliases_ascii": [],
+ "keywords": ["UK", "gb", "britsh", "nation", "united kingdom", "england", "country"]
+ },
+ "flag_gd": {
+ "unicode": "1F1EC-1F1E9",
+ "unicode_alternates": [],
+ "name": "grenada",
+ "shortname": ":flag_gd:",
+ "category": "flags",
+ "aliases": [":gd:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gd"]
+ },
+ "flag_ge": {
+ "unicode": "1F1EC-1F1EA",
+ "unicode_alternates": [],
+ "name": "georgia",
+ "shortname": ":flag_ge:",
+ "category": "flags",
+ "aliases": [":ge:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sak'art'velo", "sakartvelo", "ge"]
+ },
+ "flag_gh": {
+ "unicode": "1F1EC-1F1ED",
+ "unicode_alternates": [],
+ "name": "ghana",
+ "shortname": ":flag_gh:",
+ "category": "flags",
+ "aliases": [":gh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gh"]
+ },
+ "flag_gi": {
+ "unicode": "1F1EC-1F1EE",
+ "unicode_alternates": [],
+ "name": "gibraltar",
+ "shortname": ":flag_gi:",
+ "category": "flags",
+ "aliases": [":gi:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gi"]
+ },
+ "flag_gl": {
+ "unicode": "1F1EC-1F1F1",
+ "unicode_alternates": [],
+ "name": "greenland",
+ "shortname": ":flag_gl:",
+ "category": "flags",
+ "aliases": [":gl:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kalaallit nunaat", "gl"]
+ },
+ "flag_gm": {
+ "unicode": "1F1EC-1F1F2",
+ "unicode_alternates": [],
+ "name": "the gambia",
+ "shortname": ":flag_gm:",
+ "category": "flags",
+ "aliases": [":gm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gm"]
+ },
+ "flag_gn": {
+ "unicode": "1F1EC-1F1F3",
+ "unicode_alternates": [],
+ "name": "guinea",
+ "shortname": ":flag_gn:",
+ "category": "flags",
+ "aliases": [":gn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "guinee", "gn"]
+ },
+ "flag_gq": {
+ "unicode": "1F1EC-1F1F6",
+ "unicode_alternates": [],
+ "name": "equatorial guinea",
+ "shortname": ":flag_gq:",
+ "category": "flags",
+ "aliases": [":gq:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "guinea ecuatorial", "gq"]
+ },
+ "flag_gr": {
+ "unicode": "1F1EC-1F1F7",
+ "unicode_alternates": [],
+ "name": "greece",
+ "shortname": ":flag_gr:",
+ "category": "flags",
+ "aliases": [":gr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ellas", "ellada", "gr"]
+ },
+ "flag_gt": {
+ "unicode": "1F1EC-1F1F9",
+ "unicode_alternates": [],
+ "name": "guatemala",
+ "shortname": ":flag_gt:",
+ "category": "flags",
+ "aliases": [":gt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gt"]
+ },
+ "flag_gu": {
+ "unicode": "1F1EC-1F1FA",
+ "unicode_alternates": [],
+ "name": "guam",
+ "shortname": ":flag_gu:",
+ "category": "flags",
+ "aliases": [":gu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gu"]
+ },
+ "flag_gw": {
+ "unicode": "1F1EC-1F1FC",
+ "unicode_alternates": [],
+ "name": "guinea-bissau",
+ "shortname": ":flag_gw:",
+ "category": "flags",
+ "aliases": [":gw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "guine-bissau", "guine bissau", "gw"]
+ },
+ "flag_gy": {
+ "unicode": "1F1EC-1F1FE",
+ "unicode_alternates": [],
+ "name": "guyana",
+ "shortname": ":flag_gy:",
+ "category": "flags",
+ "aliases": [":gy:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "gy"]
+ },
+ "flag_hk": {
+ "unicode": "1F1ED-1F1F0",
+ "unicode_alternates": [],
+ "name": "hong kong",
+ "shortname": ":flag_hk:",
+ "category": "flags",
+ "aliases": [":hk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "xianggang", "hk"]
+ },
+ "flag_hn": {
+ "unicode": "1F1ED-1F1F3",
+ "unicode_alternates": [],
+ "name": "honduras",
+ "shortname": ":flag_hn:",
+ "category": "flags",
+ "aliases": [":hn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "hn"]
+ },
+ "flag_hr": {
+ "unicode": "1F1ED-1F1F7",
+ "unicode_alternates": [],
+ "name": "croatia",
+ "shortname": ":flag_hr:",
+ "category": "flags",
+ "aliases": [":hr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "hrvatska", "hr"]
+ },
+ "flag_ht": {
+ "unicode": "1F1ED-1F1F9",
+ "unicode_alternates": [],
+ "name": "haiti",
+ "shortname": ":flag_ht:",
+ "category": "flags",
+ "aliases": [":ht:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ht"]
+ },
+ "flag_hu": {
+ "unicode": "1F1ED-1F1FA",
+ "unicode_alternates": [],
+ "name": "hungary",
+ "shortname": ":flag_hu:",
+ "category": "flags",
+ "aliases": [":hu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "magyarorszag", "hu"]
+ },
+ "flag_id": {
+ "unicode": "1F1EE-1F1E9",
+ "unicode_alternates": [],
+ "name": "indonesia",
+ "shortname": ":flag_id:",
+ "category": "flags",
+ "aliases": [":indonesia:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "id"]
+ },
+ "flag_ie": {
+ "unicode": "1F1EE-1F1EA",
+ "unicode_alternates": [],
+ "name": "ireland",
+ "shortname": ":flag_ie:",
+ "category": "flags",
+ "aliases": [":ie:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "&eacute;ire", "eire", "ie"]
+ },
+ "flag_il": {
+ "unicode": "1F1EE-1F1F1",
+ "unicode_alternates": [],
+ "name": "israel",
+ "shortname": ":flag_il:",
+ "category": "flags",
+ "aliases": [":il:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "yisra'el", "yisrael", "il"]
+ },
+ "flag_in": {
+ "unicode": "1F1EE-1F1F3",
+ "unicode_alternates": [],
+ "name": "india",
+ "shortname": ":flag_in:",
+ "category": "flags",
+ "aliases": [":in:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "bharat", "in"]
+ },
+ "flag_iq": {
+ "unicode": "1F1EE-1F1F6",
+ "unicode_alternates": [],
+ "name": "iraq",
+ "shortname": ":flag_iq:",
+ "category": "flags",
+ "aliases": [":iq:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "iq"]
+ },
+ "flag_ir": {
+ "unicode": "1F1EE-1F1F7",
+ "unicode_alternates": [],
+ "name": "iran",
+ "shortname": ":flag_ir:",
+ "category": "flags",
+ "aliases": [":ir:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ir"]
+ },
+ "flag_is": {
+ "unicode": "1F1EE-1F1F8",
+ "unicode_alternates": [],
+ "name": "iceland",
+ "shortname": ":flag_is:",
+ "category": "flags",
+ "aliases": [":is:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lyoveldio island", "is"]
+ },
+ "flag_it": {
+ "unicode": "1F1EE-1F1F9",
+ "unicode_alternates": [],
+ "name": "italy",
+ "shortname": ":flag_it:",
+ "category": "flags",
+ "aliases": [":it:"],
+ "aliases_ascii": [],
+ "keywords": ["italia", "country", "nation", "it"]
+ },
+ "flag_je": {
+ "unicode": "1F1EF-1F1EA",
+ "unicode_alternates": [],
+ "name": "jersey",
+ "shortname": ":flag_je:",
+ "category": "flags",
+ "aliases": [":je:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "je"]
+ },
+ "flag_jm": {
+ "unicode": "1F1EF-1F1F2",
+ "unicode_alternates": [],
+ "name": "jamaica",
+ "shortname": ":flag_jm:",
+ "category": "flags",
+ "aliases": [":jm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "jm"]
+ },
+ "flag_jo": {
+ "unicode": "1F1EF-1F1F4",
+ "unicode_alternates": [],
+ "name": "jordan",
+ "shortname": ":flag_jo:",
+ "category": "flags",
+ "aliases": [":jo:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al urdun", "jo"]
+ },
+ "flag_jp": {
+ "unicode": "1F1EF-1F1F5",
+ "unicode_alternates": [],
+ "name": "japan",
+ "shortname": ":flag_jp:",
+ "category": "flags",
+ "aliases": [":jp:"],
+ "aliases_ascii": [],
+ "keywords": ["nation", "nippon", "country", "jp"]
+ },
+ "flag_ke": {
+ "unicode": "1F1F0-1F1EA",
+ "unicode_alternates": [],
+ "name": "kenya",
+ "shortname": ":flag_ke:",
+ "category": "flags",
+ "aliases": [":ke:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ke"]
+ },
+ "flag_kg": {
+ "unicode": "1F1F0-1F1EC",
+ "unicode_alternates": [],
+ "name": "kyrgyzstan",
+ "shortname": ":flag_kg:",
+ "category": "flags",
+ "aliases": [":kg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kyrgyz respublikasy", "kg"]
+ },
+ "flag_kh": {
+ "unicode": "1F1F0-1F1ED",
+ "unicode_alternates": [],
+ "name": "cambodia",
+ "shortname": ":flag_kh:",
+ "category": "flags",
+ "aliases": [":kh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kampuchea", "kh"]
+ },
+ "flag_ki": {
+ "unicode": "1F1F0-1F1EE",
+ "unicode_alternates": [],
+ "name": "kiribati",
+ "shortname": ":flag_ki:",
+ "category": "flags",
+ "aliases": [":ki:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kiribati", "kiribas", "ki"]
+ },
+ "flag_km": {
+ "unicode": "1F1F0-1F1F2",
+ "unicode_alternates": [],
+ "name": "the comoros",
+ "shortname": ":flag_km:",
+ "category": "flags",
+ "aliases": [":km:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "km"]
+ },
+ "flag_kn": {
+ "unicode": "1F1F0-1F1F3",
+ "unicode_alternates": [],
+ "name": "saint kitts and nevis",
+ "shortname": ":flag_kn:",
+ "category": "flags",
+ "aliases": [":kn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kn"]
+ },
+ "flag_kp": {
+ "unicode": "1F1F0-1F1F5",
+ "unicode_alternates": [],
+ "name": "north korea",
+ "shortname": ":flag_kp:",
+ "category": "flags",
+ "aliases": [":kp:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "kp"]
+ },
+ "flag_kr": {
+ "unicode": "1F1F0-1F1F7",
+ "unicode_alternates": [],
+ "name": "korea",
+ "shortname": ":flag_kr:",
+ "category": "flags",
+ "aliases": [":kr:"],
+ "aliases_ascii": [],
+ "keywords": ["nation", "country", "south korea", "kr"]
+ },
+ "flag_kw": {
+ "unicode": "1F1F0-1F1FC",
+ "unicode_alternates": [],
+ "name": "kuwait",
+ "shortname": ":flag_kw:",
+ "category": "flags",
+ "aliases": [":kw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al kuwayt", "kw"]
+ },
+ "flag_ky": {
+ "unicode": "1F1F0-1F1FE",
+ "unicode_alternates": [],
+ "name": "cayman islands",
+ "shortname": ":flag_ky:",
+ "category": "flags",
+ "aliases": [":ky:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ky"]
+ },
+ "flag_kz": {
+ "unicode": "1F1F0-1F1FF",
+ "unicode_alternates": [],
+ "name": "kazakhstan",
+ "shortname": ":flag_kz:",
+ "category": "flags",
+ "aliases": [":kz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "qazaqstan", "kz"]
+ },
+ "flag_la": {
+ "unicode": "1F1F1-1F1E6",
+ "unicode_alternates": [],
+ "name": "laos",
+ "shortname": ":flag_la:",
+ "category": "flags",
+ "aliases": [":la:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "la"]
+ },
+ "flag_lb": {
+ "unicode": "1F1F1-1F1E7",
+ "unicode_alternates": [],
+ "name": "lebanon",
+ "shortname": ":flag_lb:",
+ "category": "flags",
+ "aliases": [":lb:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lubnan", "lb"]
+ },
+ "flag_lc": {
+ "unicode": "1F1F1-1F1E8",
+ "unicode_alternates": [],
+ "name": "saint lucia",
+ "shortname": ":flag_lc:",
+ "category": "flags",
+ "aliases": [":lc:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lc"]
+ },
+ "flag_li": {
+ "unicode": "1F1F1-1F1EE",
+ "unicode_alternates": [],
+ "name": "liechtenstein",
+ "shortname": ":flag_li:",
+ "category": "flags",
+ "aliases": [":li:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "li"]
+ },
+ "flag_lk": {
+ "unicode": "1F1F1-1F1F0",
+ "unicode_alternates": [],
+ "name": "sri lanka",
+ "shortname": ":flag_lk:",
+ "category": "flags",
+ "aliases": [":lk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lk"]
+ },
+ "flag_lr": {
+ "unicode": "1F1F1-1F1F7",
+ "unicode_alternates": [],
+ "name": "liberia",
+ "shortname": ":flag_lr:",
+ "category": "flags",
+ "aliases": [":lr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lr"]
+ },
+ "flag_ls": {
+ "unicode": "1F1F1-1F1F8",
+ "unicode_alternates": [],
+ "name": "lesotho",
+ "shortname": ":flag_ls:",
+ "category": "flags",
+ "aliases": [":ls:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ls"]
+ },
+ "flag_lt": {
+ "unicode": "1F1F1-1F1F9",
+ "unicode_alternates": [],
+ "name": "lithuania",
+ "shortname": ":flag_lt:",
+ "category": "flags",
+ "aliases": [":lt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "lietuva", "lt"]
+ },
+ "flag_lu": {
+ "unicode": "1F1F1-1F1FA",
+ "unicode_alternates": [],
+ "name": "luxembourg",
+ "shortname": ":flag_lu:",
+ "category": "flags",
+ "aliases": [":lu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "luxembourg", "letzebuerg", "lu"]
+ },
+ "flag_lv": {
+ "unicode": "1F1F1-1F1FB",
+ "unicode_alternates": [],
+ "name": "latvia",
+ "shortname": ":flag_lv:",
+ "category": "flags",
+ "aliases": [":lv:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "latvija", "lv"]
+ },
+ "flag_ly": {
+ "unicode": "1F1F1-1F1FE",
+ "unicode_alternates": [],
+ "name": "libya",
+ "shortname": ":flag_ly:",
+ "category": "flags",
+ "aliases": [":ly:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "libiyah", "ly"]
+ },
+ "flag_ma": {
+ "unicode": "1F1F2-1F1E6",
+ "unicode_alternates": [],
+ "name": "morocco",
+ "shortname": ":flag_ma:",
+ "category": "flags",
+ "aliases": [":ma:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al maghrib", "ma"]
+ },
+ "flag_mc": {
+ "unicode": "1F1F2-1F1E8",
+ "unicode_alternates": [],
+ "name": "monaco",
+ "shortname": ":flag_mc:",
+ "category": "flags",
+ "aliases": [":mc:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mc"]
+ },
+ "flag_md": {
+ "unicode": "1F1F2-1F1E9",
+ "unicode_alternates": [],
+ "name": "moldova",
+ "shortname": ":flag_md:",
+ "category": "flags",
+ "aliases": [":md:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "md"]
+ },
+ "flag_me": {
+ "unicode": "1F1F2-1F1EA",
+ "unicode_alternates": [],
+ "name": "montenegro",
+ "shortname": ":flag_me:",
+ "category": "flags",
+ "aliases": [":me:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "crna gora", "me"]
+ },
+ "flag_mg": {
+ "unicode": "1F1F2-1F1EC",
+ "unicode_alternates": [],
+ "name": "madagascar",
+ "shortname": ":flag_mg:",
+ "category": "flags",
+ "aliases": [":mg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mg"]
+ },
+ "flag_mh": {
+ "unicode": "1F1F2-1F1ED",
+ "unicode_alternates": [],
+ "name": "the marshall islands",
+ "shortname": ":flag_mh:",
+ "category": "flags",
+ "aliases": [":mh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mh"]
+ },
+ "flag_mk": {
+ "unicode": "1F1F2-1F1F0",
+ "unicode_alternates": [],
+ "name": "macedonia",
+ "shortname": ":flag_mk:",
+ "category": "flags",
+ "aliases": [":mk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mk"]
+ },
+ "flag_ml": {
+ "unicode": "1F1F2-1F1F1",
+ "unicode_alternates": [],
+ "name": "mali",
+ "shortname": ":flag_ml:",
+ "category": "flags",
+ "aliases": [":ml:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ml"]
+ },
+ "flag_mm": {
+ "unicode": "1F1F2-1F1F2",
+ "unicode_alternates": [],
+ "name": "myanmar",
+ "shortname": ":flag_mm:",
+ "category": "flags",
+ "aliases": [":mm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "myanma naingngandaw", "mm"]
+ },
+ "flag_mn": {
+ "unicode": "1F1F2-1F1F3",
+ "unicode_alternates": [],
+ "name": "mongolia",
+ "shortname": ":flag_mn:",
+ "category": "flags",
+ "aliases": [":mn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mongol uls", "mn"]
+ },
+ "flag_mo": {
+ "unicode": "1F1F2-1F1F4",
+ "unicode_alternates": [],
+ "name": "macau",
+ "shortname": ":flag_mo:",
+ "category": "flags",
+ "aliases": [":mo:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "aomen", "mo"]
+ },
+ "flag_mr": {
+ "unicode": "1F1F2-1F1F7",
+ "unicode_alternates": [],
+ "name": "mauritania",
+ "shortname": ":flag_mr:",
+ "category": "flags",
+ "aliases": [":mr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "muritaniyah", "mr"]
+ },
+ "flag_ms": {
+ "unicode": "1F1F2-1F1F8",
+ "unicode_alternates": [],
+ "name": "montserrat",
+ "shortname": ":flag_ms:",
+ "category": "flags",
+ "aliases": [":ms:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ms"]
+ },
+ "flag_mt": {
+ "unicode": "1F1F2-1F1F9",
+ "unicode_alternates": [],
+ "name": "malta",
+ "shortname": ":flag_mt:",
+ "category": "flags",
+ "aliases": [":mt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mt"]
+ },
+ "flag_mu": {
+ "unicode": "1F1F2-1F1FA",
+ "unicode_alternates": [],
+ "name": "mauritius",
+ "shortname": ":flag_mu:",
+ "category": "flags",
+ "aliases": [":mu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mu"]
+ },
+ "flag_mv": {
+ "unicode": "1F1F2-1F1FB",
+ "unicode_alternates": [],
+ "name": "maldives",
+ "shortname": ":flag_mv:",
+ "category": "flags",
+ "aliases": [":mv:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "dhivehi raajje", "mv"]
+ },
+ "flag_mw": {
+ "unicode": "1F1F2-1F1FC",
+ "unicode_alternates": [],
+ "name": "malawi",
+ "shortname": ":flag_mw:",
+ "category": "flags",
+ "aliases": [":mw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mw"]
+ },
+ "flag_mx": {
+ "unicode": "1F1F2-1F1FD",
+ "unicode_alternates": [],
+ "name": "mexico",
+ "shortname": ":flag_mx:",
+ "category": "flags",
+ "aliases": [":mx:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mx"]
+ },
+ "flag_my": {
+ "unicode": "1F1F2-1F1FE",
+ "unicode_alternates": [],
+ "name": "malaysia",
+ "shortname": ":flag_my:",
+ "category": "flags",
+ "aliases": [":my:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "my"]
+ },
+ "flag_mz": {
+ "unicode": "1F1F2-1F1FF",
+ "unicode_alternates": [],
+ "name": "mozambique",
+ "shortname": ":flag_mz:",
+ "category": "flags",
+ "aliases": [":mz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "mocambique", "mz"]
+ },
+ "flag_na": {
+ "unicode": "1F1F3-1F1E6",
+ "unicode_alternates": [],
+ "name": "namibia",
+ "shortname": ":flag_na:",
+ "category": "flags",
+ "aliases": [":na:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "na"]
+ },
+ "flag_nc": {
+ "unicode": "1F1F3-1F1E8",
+ "unicode_alternates": [],
+ "name": "new caledonia",
+ "shortname": ":flag_nc:",
+ "category": "flags",
+ "aliases": [":nc:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "nouvelle", "cal&eacute;donie", "caledonie", "nc"]
+ },
+ "flag_ne": {
+ "unicode": "1F1F3-1F1EA",
+ "unicode_alternates": [],
+ "name": "niger",
+ "shortname": ":flag_ne:",
+ "category": "flags",
+ "aliases": [":ne:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ne"]
+ },
+ "flag_ng": {
+ "unicode": "1F1F3-1F1EC",
+ "unicode_alternates": [],
+ "name": "nigeria",
+ "shortname": ":flag_ng:",
+ "category": "flags",
+ "aliases": [":nigeria:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ng"]
+ },
+ "flag_ni": {
+ "unicode": "1F1F3-1F1EE",
+ "unicode_alternates": [],
+ "name": "nicaragua",
+ "shortname": ":flag_ni:",
+ "category": "flags",
+ "aliases": [":ni:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ni"]
+ },
+ "flag_nl": {
+ "unicode": "1F1F3-1F1F1",
+ "unicode_alternates": [],
+ "name": "the netherlands",
+ "shortname": ":flag_nl:",
+ "category": "flags",
+ "aliases": [":nl:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "nederland", "holland", "nl"]
+ },
+ "flag_no": {
+ "unicode": "1F1F3-1F1F4",
+ "unicode_alternates": [],
+ "name": "norway",
+ "shortname": ":flag_no:",
+ "category": "flags",
+ "aliases": [":no:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "norge", "no"]
+ },
+ "flag_np": {
+ "unicode": "1F1F3-1F1F5",
+ "unicode_alternates": [],
+ "name": "nepal",
+ "shortname": ":flag_np:",
+ "category": "flags",
+ "aliases": [":np:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "np"]
+ },
+ "flag_nr": {
+ "unicode": "1F1F3-1F1F7",
+ "unicode_alternates": [],
+ "name": "nauru",
+ "shortname": ":flag_nr:",
+ "category": "flags",
+ "aliases": [":nr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "nr"]
+ },
+ "flag_nu": {
+ "unicode": "1F1F3-1F1FA",
+ "unicode_alternates": [],
+ "name": "niue",
+ "shortname": ":flag_nu:",
+ "category": "flags",
+ "aliases": [":nu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "nu"]
+ },
+ "flag_nz": {
+ "unicode": "1F1F3-1F1FF",
+ "unicode_alternates": [],
+ "name": "new zealand",
+ "shortname": ":flag_nz:",
+ "category": "flags",
+ "aliases": [":nz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "aotearoa", "nz"]
+ },
+ "flag_om": {
+ "unicode": "1F1F4-1F1F2",
+ "unicode_alternates": [],
+ "name": "oman",
+ "shortname": ":flag_om:",
+ "category": "flags",
+ "aliases": [":om:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "saltanat uman", "om"]
+ },
+ "flag_pa": {
+ "unicode": "1F1F5-1F1E6",
+ "unicode_alternates": [],
+ "name": "panama",
+ "shortname": ":flag_pa:",
+ "category": "flags",
+ "aliases": [":pa:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pa"]
+ },
+ "flag_pe": {
+ "unicode": "1F1F5-1F1EA",
+ "unicode_alternates": [],
+ "name": "peru",
+ "shortname": ":flag_pe:",
+ "category": "flags",
+ "aliases": [":pe:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pe"]
+ },
+ "flag_pf": {
+ "unicode": "1F1F5-1F1EB",
+ "unicode_alternates": [],
+ "name": "french polynesia",
+ "shortname": ":flag_pf:",
+ "category": "flags",
+ "aliases": [":pf:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "polyn&eacute;sie fran&ccedil;aise", "polynesie francaise", "pf"]
+ },
+ "flag_pg": {
+ "unicode": "1F1F5-1F1EC",
+ "unicode_alternates": [],
+ "name": "papua new guinea",
+ "shortname": ":flag_pg:",
+ "category": "flags",
+ "aliases": [":pg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "papua niu gini", "pg"]
+ },
+ "flag_ph": {
+ "unicode": "1F1F5-1F1ED",
+ "unicode_alternates": [],
+ "name": "the philippines",
+ "shortname": ":flag_ph:",
+ "category": "flags",
+ "aliases": [":ph:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pilipinas", "ph"]
+ },
+ "flag_pk": {
+ "unicode": "1F1F5-1F1F0",
+ "unicode_alternates": [],
+ "name": "pakistan",
+ "shortname": ":flag_pk:",
+ "category": "flags",
+ "aliases": [":pk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pk"]
+ },
+ "flag_pl": {
+ "unicode": "1F1F5-1F1F1",
+ "unicode_alternates": [],
+ "name": "poland",
+ "shortname": ":flag_pl:",
+ "category": "flags",
+ "aliases": [":pl:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "polska", "pl"]
+ },
+ "flag_pr": {
+ "unicode": "1F1F5-1F1F7",
+ "unicode_alternates": [],
+ "name": "puerto rico",
+ "shortname": ":flag_pr:",
+ "category": "flags",
+ "aliases": [":pr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pr"]
+ },
+ "flag_ps": {
+ "unicode": "1F1F5-1F1F8",
+ "unicode_alternates": [],
+ "name": "palestinian authority",
+ "shortname": ":flag_ps:",
+ "category": "flags",
+ "aliases": [":ps:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ps"]
+ },
+ "flag_pt": {
+ "unicode": "1F1F5-1F1F9",
+ "unicode_alternates": [],
+ "name": "portugal",
+ "shortname": ":flag_pt:",
+ "category": "flags",
+ "aliases": [":pt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "pt"]
+ },
+ "flag_pw": {
+ "unicode": "1F1F5-1F1FC",
+ "unicode_alternates": [],
+ "name": "palau",
+ "shortname": ":flag_pw:",
+ "category": "flags",
+ "aliases": [":pw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "belau", "pw"]
+ },
+ "flag_py": {
+ "unicode": "1F1F5-1F1FE",
+ "unicode_alternates": [],
+ "name": "paraguay",
+ "shortname": ":flag_py:",
+ "category": "flags",
+ "aliases": [":py:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "py"]
+ },
+ "flag_qa": {
+ "unicode": "1F1F6-1F1E6",
+ "unicode_alternates": [],
+ "name": "qatar",
+ "shortname": ":flag_qa:",
+ "category": "flags",
+ "aliases": [":qa:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "dawlat qatar", "qa"]
+ },
+ "flag_ro": {
+ "unicode": "1F1F7-1F1F4",
+ "unicode_alternates": [],
+ "name": "romania",
+ "shortname": ":flag_ro:",
+ "category": "flags",
+ "aliases": [":ro:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ro"]
+ },
+ "flag_rs": {
+ "unicode": "1F1F7-1F1F8",
+ "unicode_alternates": [],
+ "name": "serbia",
+ "shortname": ":flag_rs:",
+ "category": "flags",
+ "aliases": [":rs:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "srbija", "rs"]
+ },
+ "flag_ru": {
+ "unicode": "1F1F7-1F1FA",
+ "unicode_alternates": [],
+ "name": "russia",
+ "shortname": ":flag_ru:",
+ "category": "flags",
+ "aliases": [":ru:"],
+ "aliases_ascii": [],
+ "keywords": ["nation", "russian", "country", "ru"]
+ },
+ "flag_rw": {
+ "unicode": "1F1F7-1F1FC",
+ "unicode_alternates": [],
+ "name": "rwanda",
+ "shortname": ":flag_rw:",
+ "category": "flags",
+ "aliases": [":rw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "rw"]
+ },
+ "flag_sa": {
+ "unicode": "1F1F8-1F1E6",
+ "unicode_alternates": [],
+ "name": "saudi arabia",
+ "shortname": ":flag_sa:",
+ "category": "flags",
+ "aliases": [":saudiarabia:", ":saudi:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al arabiyah as suudiyah", "sa"]
+ },
+ "flag_sb": {
+ "unicode": "1F1F8-1F1E7",
+ "unicode_alternates": [],
+ "name": "the solomon islands",
+ "shortname": ":flag_sb:",
+ "category": "flags",
+ "aliases": [":sb:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sb"]
+ },
+ "flag_sc": {
+ "unicode": "1F1F8-1F1E8",
+ "unicode_alternates": [],
+ "name": "the seychelles",
+ "shortname": ":flag_sc:",
+ "category": "flags",
+ "aliases": [":sc:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "seychelles", "sc"]
+ },
+ "flag_sd": {
+ "unicode": "1F1F8-1F1E9",
+ "unicode_alternates": [],
+ "name": "sudan",
+ "shortname": ":flag_sd:",
+ "category": "flags",
+ "aliases": [":sd:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "as-sudan", "sd"]
+ },
+ "flag_se": {
+ "unicode": "1F1F8-1F1EA",
+ "unicode_alternates": [],
+ "name": "sweden",
+ "shortname": ":flag_se:",
+ "category": "flags",
+ "aliases": [":se:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sverige", "se"]
+ },
+ "flag_sg": {
+ "unicode": "1F1F8-1F1EC",
+ "unicode_alternates": [],
+ "name": "singapore",
+ "shortname": ":flag_sg:",
+ "category": "flags",
+ "aliases": [":sg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sg"]
+ },
+ "flag_sh": {
+ "unicode": "1F1F8-1F1ED",
+ "unicode_alternates": [],
+ "name": "saint helena",
+ "shortname": ":flag_sh:",
+ "category": "flags",
+ "aliases": [":sh:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sh"]
+ },
+ "flag_si": {
+ "unicode": "1F1F8-1F1EE",
+ "unicode_alternates": [],
+ "name": "slovenia",
+ "shortname": ":flag_si:",
+ "category": "flags",
+ "aliases": [":si:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "slovenija", "si"]
+ },
+ "flag_sk": {
+ "unicode": "1F1F8-1F1F0",
+ "unicode_alternates": [],
+ "name": "slovakia",
+ "shortname": ":flag_sk:",
+ "category": "flags",
+ "aliases": [":sk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sk"]
+ },
+ "flag_sl": {
+ "unicode": "1F1F8-1F1F1",
+ "unicode_alternates": [],
+ "name": "sierra leone",
+ "shortname": ":flag_sl:",
+ "category": "flags",
+ "aliases": [":sl:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sl"]
+ },
+ "flag_sm": {
+ "unicode": "1F1F8-1F1F2",
+ "unicode_alternates": [],
+ "name": "san marino",
+ "shortname": ":flag_sm:",
+ "category": "flags",
+ "aliases": [":sm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sm"]
+ },
+ "flag_sn": {
+ "unicode": "1F1F8-1F1F3",
+ "unicode_alternates": [],
+ "name": "senegal",
+ "shortname": ":flag_sn:",
+ "category": "flags",
+ "aliases": [":sn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sn"]
+ },
+ "flag_so": {
+ "unicode": "1F1F8-1F1F4",
+ "unicode_alternates": [],
+ "name": "somalia",
+ "shortname": ":flag_so:",
+ "category": "flags",
+ "aliases": [":so:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "so"]
+ },
+ "flag_sr": {
+ "unicode": "1F1F8-1F1F7",
+ "unicode_alternates": [],
+ "name": "suriname",
+ "shortname": ":flag_sr:",
+ "category": "flags",
+ "aliases": [":sr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sr"]
+ },
+ "flag_st": {
+ "unicode": "1F1F8-1F1F9",
+ "unicode_alternates": [],
+ "name": "sao tome and principe",
+ "shortname": ":flag_st:",
+ "category": "flags",
+ "aliases": [":st:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sao tome e principe", "st"]
+ },
+ "flag_sv": {
+ "unicode": "1F1F8-1F1FB",
+ "unicode_alternates": [],
+ "name": "el salvador",
+ "shortname": ":flag_sv:",
+ "category": "flags",
+ "aliases": [":sv:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sv"]
+ },
+ "flag_sy": {
+ "unicode": "1F1F8-1F1FE",
+ "unicode_alternates": [],
+ "name": "syria",
+ "shortname": ":flag_sy:",
+ "category": "flags",
+ "aliases": [":sy:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sy"]
+ },
+ "flag_sz": {
+ "unicode": "1F1F8-1F1FF",
+ "unicode_alternates": [],
+ "name": "swaziland",
+ "shortname": ":flag_sz:",
+ "category": "flags",
+ "aliases": [":sz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "sz"]
+ },
+ "flag_td": {
+ "unicode": "1F1F9-1F1E9",
+ "unicode_alternates": [],
+ "name": "chad",
+ "shortname": ":flag_td:",
+ "category": "flags",
+ "aliases": [":td:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tchad", "td"]
+ },
+ "flag_tg": {
+ "unicode": "1F1F9-1F1EC",
+ "unicode_alternates": [],
+ "name": "togo",
+ "shortname": ":flag_tg:",
+ "category": "flags",
+ "aliases": [":tg:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "republique togolaise", "tg"]
+ },
+ "flag_th": {
+ "unicode": "1F1F9-1F1ED",
+ "unicode_alternates": [],
+ "name": "thailand",
+ "shortname": ":flag_th:",
+ "category": "flags",
+ "aliases": [":th:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "prathet thai", "th"]
+ },
+ "flag_tj": {
+ "unicode": "1F1F9-1F1EF",
+ "unicode_alternates": [],
+ "name": "tajikistan",
+ "shortname": ":flag_tj:",
+ "category": "flags",
+ "aliases": [":tj:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "jumhurii tojikiston", "tj"]
+ },
+ "flag_tl": {
+ "unicode": "1F1F9-1F1F1",
+ "unicode_alternates": [],
+ "name": "east timor",
+ "shortname": ":flag_tl:",
+ "category": "flags",
+ "aliases": [":tl:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tl"]
+ },
+ "flag_tm": {
+ "unicode": "1F1F9-1F1F2",
+ "unicode_alternates": [],
+ "name": "turkmenistan",
+ "shortname": ":flag_tm:",
+ "category": "flags",
+ "aliases": [":turkmenistan:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tm"]
+ },
+ "flag_tn": {
+ "unicode": "1F1F9-1F1F3",
+ "unicode_alternates": [],
+ "name": "tunisia",
+ "shortname": ":flag_tn:",
+ "category": "flags",
+ "aliases": [":tn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tunis", "tn"]
+ },
+ "flag_to": {
+ "unicode": "1F1F9-1F1F4",
+ "unicode_alternates": [],
+ "name": "tonga",
+ "shortname": ":flag_to:",
+ "category": "flags",
+ "aliases": [":to:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "to"]
+ },
+ "flag_tr": {
+ "unicode": "1F1F9-1F1F7",
+ "unicode_alternates": [],
+ "name": "turkey",
+ "shortname": ":flag_tr:",
+ "category": "flags",
+ "aliases": [":tr:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "turkiye"]
+ },
+ "flag_tt": {
+ "unicode": "1F1F9-1F1F9",
+ "unicode_alternates": [],
+ "name": "trinidad and tobago",
+ "shortname": ":flag_tt:",
+ "category": "flags",
+ "aliases": [":tt:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tt"]
+ },
+ "flag_tv": {
+ "unicode": "1F1F9-1F1FB",
+ "unicode_alternates": [],
+ "name": "tuvalu",
+ "shortname": ":flag_tv:",
+ "category": "flags",
+ "aliases": [":tuvalu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tv"]
+ },
+ "flag_tw": {
+ "unicode": "1F1F9-1F1FC",
+ "unicode_alternates": [],
+ "name": "the republic of china",
+ "shortname": ":flag_tw:",
+ "category": "flags",
+ "aliases": [":tw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "taiwan", "tw"]
+ },
+ "flag_tz": {
+ "unicode": "1F1F9-1F1FF",
+ "unicode_alternates": [],
+ "name": "tanzania",
+ "shortname": ":flag_tz:",
+ "category": "flags",
+ "aliases": [":tz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "tz"]
+ },
+ "flag_ua": {
+ "unicode": "1F1FA-1F1E6",
+ "unicode_alternates": [],
+ "name": "ukraine",
+ "shortname": ":flag_ua:",
+ "category": "flags",
+ "aliases": [":ua:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ukrayina", "ua"]
+ },
+ "flag_ug": {
+ "unicode": "1F1FA-1F1EC",
+ "unicode_alternates": [],
+ "name": "uganda",
+ "shortname": ":flag_ug:",
+ "category": "flags",
+ "aliases": [":ug:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ug"]
+ },
+ "flag_us": {
+ "unicode": "1F1FA-1F1F8",
+ "unicode_alternates": [],
+ "name": "united states",
+ "shortname": ":flag_us:",
+ "category": "flags",
+ "aliases": [":us:"],
+ "aliases_ascii": [],
+ "keywords": ["american", "country", "nation", "usa", "united states of america", "america", "old glory", "us"]
+ },
+ "flag_uy": {
+ "unicode": "1F1FA-1F1FE",
+ "unicode_alternates": [],
+ "name": "uruguay",
+ "shortname": ":flag_uy:",
+ "category": "flags",
+ "aliases": [":uy:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "uy"]
+ },
+ "flag_uz": {
+ "unicode": "1F1FA-1F1FF",
+ "unicode_alternates": [],
+ "name": "uzbekistan",
+ "shortname": ":flag_uz:",
+ "category": "flags",
+ "aliases": [":uz:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "uzbekiston respublikasi", "uz"]
+ },
+ "flag_va": {
+ "unicode": "1F1FB-1F1E6",
+ "unicode_alternates": [],
+ "name": "the vatican city",
+ "shortname": ":flag_va:",
+ "category": "flags",
+ "aliases": [":va:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "va"]
+ },
+ "flag_vc": {
+ "unicode": "1F1FB-1F1E8",
+ "unicode_alternates": [],
+ "name": "saint vincent and the grenadines",
+ "shortname": ":flag_vc:",
+ "category": "flags",
+ "aliases": [":vc:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "vc"]
+ },
+ "flag_ve": {
+ "unicode": "1F1FB-1F1EA",
+ "unicode_alternates": [],
+ "name": "venezuela",
+ "shortname": ":flag_ve:",
+ "category": "flags",
+ "aliases": [":ve:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "ve"]
+ },
+ "flag_vi": {
+ "unicode": "1F1FB-1F1EE",
+ "unicode_alternates": [],
+ "name": "u.s. virgin islands",
+ "shortname": ":flag_vi:",
+ "category": "flags",
+ "aliases": [":vi:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "vi"]
+ },
+ "flag_vn": {
+ "unicode": "1F1FB-1F1F3",
+ "unicode_alternates": [],
+ "name": "vietnam",
+ "shortname": ":flag_vn:",
+ "category": "flags",
+ "aliases": [":vn:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "viet nam", "vn"]
+ },
+ "flag_vu": {
+ "unicode": "1F1FB-1F1FA",
+ "unicode_alternates": [],
+ "name": "vanuatu",
+ "shortname": ":flag_vu:",
+ "category": "flags",
+ "aliases": [":vu:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "vu"]
+ },
+ "flag_wf": {
+ "unicode": "1F1FC-1F1EB",
+ "unicode_alternates": [],
+ "name": "wallis and futuna",
+ "shortname": ":flag_wf:",
+ "category": "flags",
+ "aliases": [":wf:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "wf"]
+ },
+ "flag_white": {
+ "unicode": "1F3F3",
+ "unicode_alternates": [],
+ "name": "waving white flag",
+ "shortname": ":flag_white:",
+ "category": "objects_symbols",
+ "aliases": [":waving_white_flag:"],
+ "aliases_ascii": [],
+ "keywords": ["symbol", "signal"]
+ },
+ "flag_ws": {
+ "unicode": "1F1FC-1F1F8",
+ "unicode_alternates": [],
+ "name": "samoa",
+ "shortname": ":flag_ws:",
+ "category": "flags",
+ "aliases": [":ws:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "american samoa", "ws"]
+ },
+ "flag_xk": {
+ "unicode": "1F1FD-1F1F0",
+ "unicode_alternates": [],
+ "name": "kosovo",
+ "shortname": ":flag_xk:",
+ "category": "flags",
+ "aliases": [":xk:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "xk"]
+ },
+ "flag_ye": {
+ "unicode": "1F1FE-1F1EA",
+ "unicode_alternates": [],
+ "name": "yemen",
+ "shortname": ":flag_ye:",
+ "category": "flags",
+ "aliases": [":ye:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "al yaman", "ye"]
+ },
+ "flag_za": {
+ "unicode": "1F1FF-1F1E6",
+ "unicode_alternates": [],
+ "name": "south africa",
+ "shortname": ":flag_za:",
+ "category": "flags",
+ "aliases": [":za:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation"]
+ },
+ "flag_zm": {
+ "unicode": "1F1FF-1F1F2",
+ "unicode_alternates": [],
+ "name": "zambia",
+ "shortname": ":flag_zm:",
+ "category": "flags",
+ "aliases": [":zm:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "zm"]
+ },
+ "flag_zw": {
+ "unicode": "1F1FF-1F1FC",
+ "unicode_alternates": [],
+ "name": "zimbabwe",
+ "shortname": ":flag_zw:",
+ "category": "flags",
+ "aliases": [":zw:"],
+ "aliases_ascii": [],
+ "keywords": ["country", "nation", "zw"]
+ },
+ "flags": {
+ "unicode": "1F38F",
+ "unicode_alternates": [],
+ "name": "carp streamer",
+ "shortname": ":flags:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["banner", "carp", "fish", "japanese", "koinobori", "children", "kids", "boys", "celebration", "happiness", "carp", "streamers", "japanese", "holiday", "flags"],
+ "moji": "🎏"
+ },
+ "flashlight": {
+ "unicode": "1F526",
+ "unicode_alternates": [],
+ "name": "electric torch",
+ "shortname": ":flashlight:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dark"],
+ "moji": "🔦"
+ },
+ "flip_phone": {
+ "unicode": "1F581",
+ "unicode_alternates": [],
+ "name": "clamshell mobile phone",
+ "shortname": ":flip_phone:",
+ "category": "objects_symbols",
+ "aliases": [":clamshell_mobile_phone:"],
+ "aliases_ascii": [],
+ "keywords": ["cellphone"]
+ },
+ "floppy_black": {
+ "unicode": "1F5AA",
+ "unicode_alternates": [],
+ "name": "black hard shell floppy disk",
+ "shortname": ":floppy_black:",
+ "category": "objects_symbols",
+ "aliases": [":black_hard_shell_floppy_disk:"],
+ "aliases_ascii": [],
+ "keywords": ["oldschool", "save", "technology", "storage", "information", "computer", "drive", "megabyte"]
+ },
+ "floppy_disk": {
+ "unicode": "1F4BE",
+ "unicode_alternates": [],
+ "name": "floppy disk",
+ "shortname": ":floppy_disk:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["oldschool", "save", "technology", "floppy", "disk", "storage", "information", "computer", "drive", "megabyte"],
+ "moji": "💾"
+ },
+ "floppy_white": {
+ "unicode": "1F5AB",
+ "unicode_alternates": [],
+ "name": "white hard shell floppy disk",
+ "shortname": ":floppy_white:",
+ "category": "objects_symbols",
+ "aliases": [":white_hard_shell_floppy_disk:"],
+ "aliases_ascii": [],
+ "keywords": ["oldschool", "save", "technology", "storage", "information", "computer", "drive", "megabyte"]
+ },
+ "flower_playing_cards": {
+ "unicode": "1F3B4",
+ "unicode_alternates": [],
+ "name": "flower playing cards",
+ "shortname": ":flower_playing_cards:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["playing", "card", "flower", "game", "august", "moon", "special"],
+ "moji": "🎴"
+ },
+ "flushed": {
+ "unicode": "1F633",
+ "unicode_alternates": [],
+ "name": "flushed face",
+ "shortname": ":flushed:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":$", "=$"],
+ "keywords": ["blush", "face", "flattered", "flush", "blush", "red", "pink", "cheeks", "shy"],
+ "moji": "😳"
+ },
+ "fog": {
+ "unicode": "1F32B",
+ "unicode_alternates": [],
+ "name": "fog",
+ "shortname": ":fog:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["weather", "damp", "cloud", "hazy"]
+ },
+ "foggy": {
+ "unicode": "1F301",
+ "unicode_alternates": [],
+ "name": "foggy",
+ "shortname": ":foggy:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mountain", "photo", "bridge", "weather", "fog", "foggy"],
+ "moji": "🌁"
+ },
+ "folder": {
+ "unicode": "1F5C0",
+ "unicode_alternates": [],
+ "name": "folder",
+ "shortname": ":folder:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"]
+ },
+ "folder_open": {
+ "unicode": "1F5C1",
+ "unicode_alternates": [],
+ "name": "open folder",
+ "shortname": ":folder_open:",
+ "category": "objects_symbols",
+ "aliases": [":open_folder:"],
+ "aliases_ascii": [],
+ "keywords": ["documents", "load"]
+ },
+ "football": {
+ "unicode": "1F3C8",
+ "unicode_alternates": [],
+ "name": "american football",
+ "shortname": ":football:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["NFL", "balls", "sports", "football", "ball", "sport", "america", "american"],
+ "moji": "🏈"
+ },
+ "footprints": {
+ "unicode": "1F463",
+ "unicode_alternates": [],
+ "name": "footprints",
+ "shortname": ":footprints:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["feet"],
+ "moji": "👣"
+ },
+ "fork_and_knife": {
+ "unicode": "1F374",
+ "unicode_alternates": [],
+ "name": "fork and knife",
+ "shortname": ":fork_and_knife:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cutlery", "kitchen", "fork", "knife", "restaurant", "meal", "food", "eat"],
+ "moji": "🍴"
+ },
+ "fork_knife_plate": {
+ "unicode": "1F37D",
+ "unicode_alternates": [],
+ "name": "fork and knife with plate",
+ "shortname": ":fork_knife_plate:",
+ "category": "travel_places",
+ "aliases": [":fork_and_knife_with_plate:"],
+ "aliases_ascii": [],
+ "keywords": ["meal", "food", "breakfast", "lunch", "dinner", "utensils", "setting"]
+ },
+ "fountain": {
+ "unicode": "26F2",
+ "unicode_alternates": ["26F2-FE0F"],
+ "name": "fountain",
+ "shortname": ":fountain:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo"],
+ "moji": "⛲"
+ },
+ "four": {
+ "moji": "4️⃣",
+ "unicode": "0034-20E3",
+ "unicode_alternates": ["0034-FE0F-20E3"],
+ "name": "digit four",
+ "shortname": ":four:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["4", "blue-square", "numbers"]
+ },
+ "four_leaf_clover": {
+ "unicode": "1F340",
+ "unicode_alternates": [],
+ "name": "four leaf clover",
+ "shortname": ":four_leaf_clover:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["lucky", "nature", "plant", "vegetable", "clover", "four", "leaf", "luck", "irish", "saint", "patrick", "green"],
+ "moji": "🍀"
+ },
+ "frame_photo": {
+ "unicode": "1F5BC",
+ "unicode_alternates": [],
+ "name": "frame with picture",
+ "shortname": ":frame_photo:",
+ "category": "objects_symbols",
+ "aliases": [":frame_with_picture:"],
+ "aliases_ascii": [],
+ "keywords": ["photo"]
+ },
+ "frame_tiles": {
+ "unicode": "1F5BD",
+ "unicode_alternates": [],
+ "name": "frame with tiles",
+ "shortname": ":frame_tiles:",
+ "category": "objects_symbols",
+ "aliases": [":frame_with_tiles:"],
+ "aliases_ascii": [],
+ "keywords": ["photo", "painting"]
+ },
+ "frame_x": {
+ "unicode": "1F5BE",
+ "unicode_alternates": [],
+ "name": "frame with an x",
+ "shortname": ":frame_x:",
+ "category": "objects_symbols",
+ "aliases": [":frame_with_an_x:"],
+ "aliases_ascii": [],
+ "keywords": ["photo", "painting"]
+ },
+ "free": {
+ "unicode": "1F193",
+ "unicode_alternates": [],
+ "name": "squared free",
+ "shortname": ":free:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "words"],
+ "moji": "🆓"
+ },
+ "fried_shrimp": {
+ "unicode": "1F364",
+ "unicode_alternates": [],
+ "name": "fried shrimp",
+ "shortname": ":fried_shrimp:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "food", "shrimp", "fried", "seafood", "small", "fish"],
+ "moji": "🍤"
+ },
+ "fries": {
+ "unicode": "1F35F",
+ "unicode_alternates": [],
+ "name": "french fries",
+ "shortname": ":fries:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chips", "food", "fries", "french", "potato", "fry", "russet", "idaho"],
+ "moji": "🍟"
+ },
+ "frog": {
+ "unicode": "1F438",
+ "unicode_alternates": [],
+ "name": "frog face",
+ "shortname": ":frog:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐸"
+ },
+ "frowning": {
+ "unicode": "1F626",
+ "unicode_alternates": [],
+ "name": "frowning face with open mouth",
+ "shortname": ":frowning:",
+ "category": "emoticons",
+ "aliases": [":anguished:"],
+ "aliases_ascii": [],
+ "keywords": ["aw", "face", "frown", "sad", "pout", "sulk", "glower"],
+ "moji": "😦"
+ },
+ "fuelpump": {
+ "unicode": "26FD",
+ "unicode_alternates": ["26FD-FE0F"],
+ "name": "fuel pump",
+ "shortname": ":fuelpump:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gas station", "petroleum"],
+ "moji": "⛽"
+ },
+ "full_moon": {
+ "unicode": "1F315",
+ "unicode_alternates": [],
+ "name": "full moon symbol",
+ "shortname": ":full_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "yellow", "moon", "full", "sky", "night", "cheese", "phase", "monster", "spooky", "werewolves", "twilight"],
+ "moji": "🌕"
+ },
+ "full_moon_with_face": {
+ "unicode": "1F31D",
+ "unicode_alternates": [],
+ "name": "full moon with face",
+ "shortname": ":full_moon_with_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "moon", "full", "anthropomorphic", "face", "sky", "night", "cheese", "phase", "spooky", "werewolves", "monsters"],
+ "moji": "🌝"
+ },
+ "game_die": {
+ "unicode": "1F3B2",
+ "unicode_alternates": [],
+ "name": "game die",
+ "shortname": ":game_die:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dice", "game", "die", "dice", "craps", "gamble", "play"],
+ "moji": "🎲"
+ },
+ "gem": {
+ "unicode": "1F48E",
+ "unicode_alternates": [],
+ "name": "gem stone",
+ "shortname": ":gem:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue", "ruby"],
+ "moji": "💎"
+ },
+ "gemini": {
+ "unicode": "264A",
+ "unicode_alternates": ["264A-FE0F"],
+ "name": "gemini",
+ "shortname": ":gemini:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gemini", "twins", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "sign", "zodiac", "horoscope"],
+ "moji": "♊"
+ },
+ "ghost": {
+ "unicode": "1F47B",
+ "unicode_alternates": [],
+ "name": "ghost",
+ "shortname": ":ghost:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["halloween"],
+ "moji": "👻"
+ },
+ "gift": {
+ "unicode": "1F381",
+ "unicode_alternates": [],
+ "name": "wrapped present",
+ "shortname": ":gift:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["birthday", "christmas", "present", "xmas", "gift", "present", "wrap", "package", "birthday", "wedding"],
+ "moji": "🎁"
+ },
+ "gift_heart": {
+ "unicode": "1F49D",
+ "unicode_alternates": [],
+ "name": "heart with ribbon",
+ "shortname": ":gift_heart:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["love", "valentines"],
+ "moji": "💝"
+ },
+ "girl": {
+ "unicode": "1F467",
+ "unicode_alternates": [],
+ "name": "girl",
+ "shortname": ":girl:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "woman"],
+ "moji": "👧"
+ },
+ "girls_symbol": {
+ "unicode": "1F6CA",
+ "unicode_alternates": [],
+ "name": "girls symbol",
+ "shortname": ":girls_symbol:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "child"]
+ },
+ "globe_with_meridians": {
+ "unicode": "1F310",
+ "unicode_alternates": [],
+ "name": "globe with meridians",
+ "shortname": ":globe_with_meridians:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["earth", "international", "world", "earth", "meridian", "globe", "space", "planet", "home"],
+ "moji": "🌐"
+ },
+ "goat": {
+ "unicode": "1F410",
+ "unicode_alternates": [],
+ "name": "goat",
+ "shortname": ":goat:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "goat", "sheep", "kid", "billy", "livestock"],
+ "moji": "🐐"
+ },
+ "golf": {
+ "unicode": "26F3",
+ "unicode_alternates": ["26F3-FE0F"],
+ "name": "flag in hole",
+ "shortname": ":golf:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["business", "sports"],
+ "moji": "⛳"
+ },
+ "golfer": {
+ "unicode": "1F3CC",
+ "unicode_alternates": [],
+ "name": "golfer",
+ "shortname": ":golfer:",
+ "category": "activity",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sport", "par", "birdie", "eagle", "mulligan"]
+ },
+ "grapes": {
+ "unicode": "1F347",
+ "unicode_alternates": [],
+ "name": "grapes",
+ "shortname": ":grapes:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "grapes", "wine", "vinegar", "fruit", "cluster", "vine"],
+ "moji": "🍇"
+ },
+ "green_apple": {
+ "unicode": "1F34F",
+ "unicode_alternates": [],
+ "name": "green apple",
+ "shortname": ":green_apple:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fruit", "nature", "apple", "fruit", "green", "pie", "granny", "smith", "core"],
+ "moji": "🍏"
+ },
+ "green_book": {
+ "unicode": "1F4D7",
+ "unicode_alternates": [],
+ "name": "green book",
+ "shortname": ":green_book:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["knowledge", "library", "read"],
+ "moji": "📗"
+ },
+ "green_heart": {
+ "unicode": "1F49A",
+ "unicode_alternates": [],
+ "name": "green heart",
+ "shortname": ":green_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "green", "heart", "love", "nature", "rebirth", "reborn", "jealous", "clingy", "envious", "possessive"],
+ "moji": "💚"
+ },
+ "grey_exclamation": {
+ "unicode": "2755",
+ "unicode_alternates": [],
+ "name": "white exclamation mark ornament",
+ "shortname": ":grey_exclamation:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["surprise"],
+ "moji": "❕"
+ },
+ "grey_question": {
+ "unicode": "2754",
+ "unicode_alternates": [],
+ "name": "white question mark ornament",
+ "shortname": ":grey_question:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["doubts"],
+ "moji": "❔"
+ },
+ "grimacing": {
+ "unicode": "1F62C",
+ "unicode_alternates": [],
+ "name": "grimacing face",
+ "shortname": ":grimacing:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "grimace", "teeth", "grimace", "disapprove", "pain"],
+ "moji": "😬"
+ },
+ "grin": {
+ "unicode": "1F601",
+ "unicode_alternates": [],
+ "name": "grinning face with smiling eyes",
+ "shortname": ":grin:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "happy", "joy", "smile", "grin", "grinning", "smiling", "smile", "smiley"],
+ "moji": "😁"
+ },
+ "grinning": {
+ "unicode": "1F600",
+ "unicode_alternates": [],
+ "name": "grinning face",
+ "shortname": ":grinning:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "happy", "joy", "smile", "grin", "grinning", "smiling", "smile", "smiley"],
+ "moji": "🕧"
+ },
+ "guardsman": {
+ "unicode": "1F482",
+ "unicode_alternates": [],
+ "name": "guardsman",
+ "shortname": ":guardsman:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["british", "gb", "male", "man", "uk", "guardsman", "guard", "bearskin", "hat", "british", "queen", "ceremonial", "military"],
+ "moji": "💂"
+ },
+ "guitar": {
+ "unicode": "1F3B8",
+ "unicode_alternates": [],
+ "name": "guitar",
+ "shortname": ":guitar:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["instrument", "music", "guitar", "string", "music", "instrument", "jam", "rock", "acoustic", "electric"],
+ "moji": "🎸"
+ },
+ "gun": {
+ "unicode": "1F52B",
+ "unicode_alternates": [],
+ "name": "pistol",
+ "shortname": ":gun:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["violence", "weapon"],
+ "moji": "🔫"
+ },
+ "haircut": {
+ "unicode": "1F487",
+ "unicode_alternates": [],
+ "name": "haircut",
+ "shortname": ":haircut:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman"],
+ "moji": "💇"
+ },
+ "hamburger": {
+ "unicode": "1F354",
+ "unicode_alternates": [],
+ "name": "hamburger",
+ "shortname": ":hamburger:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "meat", "hamburger", "burger", "meat", "cow", "beef"],
+ "moji": "🍔"
+ },
+ "hammer": {
+ "unicode": "1F528",
+ "unicode_alternates": [],
+ "name": "hammer",
+ "shortname": ":hammer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["done", "judge", "law", "ruling", "tools", "verdict"],
+ "moji": "🔨"
+ },
+ "hamster": {
+ "unicode": "1F439",
+ "unicode_alternates": [],
+ "name": "hamster face",
+ "shortname": ":hamster:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐹"
+ },
+ "hand_splayed": {
+ "unicode": "1F590",
+ "unicode_alternates": [],
+ "name": "raised hand with fingers splayed",
+ "shortname": ":hand_splayed:",
+ "category": "people",
+ "aliases": [":raised_hand_with_fingers_splayed:"],
+ "aliases_ascii": [],
+ "keywords": ["hi", "five", "stop", "halt"]
+ },
+ "hand_splayed_reverse": {
+ "unicode": "1F591",
+ "unicode_alternates": [],
+ "name": "reversed raised hand with fingers splayed",
+ "shortname": ":hand_splayed_reverse:",
+ "category": "people",
+ "aliases": [":reversed_raised_hand_with_fingers_splayed:"],
+ "aliases_ascii": [],
+ "keywords": ["hi", "five", "stop", "halt"]
+ },
+ "hand_victory": {
+ "unicode": "1F594",
+ "unicode_alternates": [],
+ "name": "reversed victory hand",
+ "shortname": ":hand_victory:",
+ "category": "people",
+ "aliases": [":reversed_victory_hand:"],
+ "aliases_ascii": [],
+ "keywords": ["fu"]
+ },
+ "handbag": {
+ "unicode": "1F45C",
+ "unicode_alternates": [],
+ "name": "handbag",
+ "shortname": ":handbag:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "accessory", "bag", "fashion"],
+ "moji": "👜"
+ },
+ "hard_disk": {
+ "unicode": "1F5B4",
+ "unicode_alternates": [],
+ "name": "hard disk",
+ "shortname": ":hard_disk:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["save", "technology", "storage", "information", "computer", "drive", "megabyte", "gigabyte", "hd"]
+ },
+ "hash": {
+ "moji": "#⃣",
+ "unicode": "0023-20E3",
+ "unicode_alternates": ["0023-FE0F-20E3"],
+ "name": "number sign",
+ "shortname": ":hash:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["symbol"]
+ },
+ "hatched_chick": {
+ "unicode": "1F425",
+ "unicode_alternates": [],
+ "name": "front-facing baby chick",
+ "shortname": ":hatched_chick:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["baby", "chicken", "chick", "baby", "bird", "chicken", "young", "woman", "cute"],
+ "moji": "🐥"
+ },
+ "hatching_chick": {
+ "unicode": "1F423",
+ "unicode_alternates": [],
+ "name": "hatching chick",
+ "shortname": ":hatching_chick:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["born", "chicken", "egg", "chick", "egg", "baby", "bird", "chicken", "young", "woman", "cute"],
+ "moji": "🐣"
+ },
+ "headphones": {
+ "unicode": "1F3A7",
+ "unicode_alternates": [],
+ "name": "headphone",
+ "shortname": ":headphones:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gadgets", "music", "score", "headphone", "sound", "music", "ears", "beats", "buds", "audio", "listen"],
+ "moji": "🎧"
+ },
+ "hear_no_evil": {
+ "unicode": "1F649",
+ "unicode_alternates": [],
+ "name": "hear-no-evil monkey",
+ "shortname": ":hear_no_evil:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "monkey", "monkey", "ears", "hear", "sound", "kikazaru"],
+ "moji": "🙉"
+ },
+ "heart": {
+ "moji": "❤",
+ "unicode": "2764",
+ "unicode_alternates": ["2764-FE0F"],
+ "name": "heavy black heart",
+ "shortname": ":heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["<3"],
+ "keywords": ["like", "love", "red", "pink", "black", "heart", "love", "passion", "romance", "intense", "desire", "death", "evil", "cold", "valentines"]
+ },
+ "heart_decoration": {
+ "unicode": "1F49F",
+ "unicode_alternates": [],
+ "name": "heart decoration",
+ "shortname": ":heart_decoration:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["like", "love", "purple-square"],
+ "moji": "💟"
+ },
+ "heart_eyes": {
+ "unicode": "1F60D",
+ "unicode_alternates": [],
+ "name": "smiling face with heart-shaped eyes",
+ "shortname": ":heart_eyes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "crush", "face", "infatuation", "like", "love", "valentines", "smiling", "heart", "lovestruck", "love", "flirt", "smile", "heart-shaped"],
+ "moji": "😍"
+ },
+ "heart_eyes_cat": {
+ "unicode": "1F63B",
+ "unicode_alternates": [],
+ "name": "smiling cat face with heart-shaped eyes",
+ "shortname": ":heart_eyes_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "animal", "cats", "like", "love", "valentines", "lovestruck", "love", "heart"],
+ "moji": "😻"
+ },
+ "heart_tip": {
+ "unicode": "1F394",
+ "unicode_alternates": [],
+ "name": "heart with tip on the left",
+ "shortname": ":heart_tip:",
+ "category": "celebration",
+ "aliases": [":heart_with_tip_on_the_left:"],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines"]
+ },
+ "heartbeat": {
+ "unicode": "1F493",
+ "unicode_alternates": [],
+ "name": "beating heart",
+ "shortname": ":heartbeat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines"],
+ "moji": "💓"
+ },
+ "heartpulse": {
+ "unicode": "1F497",
+ "unicode_alternates": [],
+ "name": "growing heart",
+ "shortname": ":heartpulse:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines"],
+ "moji": "💗"
+ },
+ "hearts": {
+ "unicode": "2665",
+ "unicode_alternates": ["2665-FE0F"],
+ "name": "black heart suit",
+ "shortname": ":hearts:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cards", "poker"],
+ "moji": "♥"
+ },
+ "heavy_check_mark": {
+ "unicode": "2714",
+ "unicode_alternates": ["2714-FE0F"],
+ "name": "heavy check mark",
+ "shortname": ":heavy_check_mark:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nike", "ok"],
+ "moji": "✔"
+ },
+ "heavy_division_sign": {
+ "unicode": "2797",
+ "unicode_alternates": [],
+ "name": "heavy division sign",
+ "shortname": ":heavy_division_sign:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["calculation", "divide", "math"],
+ "moji": "➗"
+ },
+ "heavy_dollar_sign": {
+ "unicode": "1F4B2",
+ "unicode_alternates": [],
+ "name": "heavy dollar sign",
+ "shortname": ":heavy_dollar_sign:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["currency", "money", "payment", "dollar", "currency", "money", "cash", "sale", "purchase", "value"],
+ "moji": "💲"
+ },
+ "heavy_minus_sign": {
+ "unicode": "2796",
+ "unicode_alternates": [],
+ "name": "heavy minus sign",
+ "shortname": ":heavy_minus_sign:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["calculation", "math"],
+ "moji": "➖"
+ },
+ "heavy_multiplication_x": {
+ "unicode": "2716",
+ "unicode_alternates": ["2716-FE0F"],
+ "name": "heavy multiplication x",
+ "shortname": ":heavy_multiplication_x:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["calculation", "math"],
+ "moji": "✖"
+ },
+ "heavy_plus_sign": {
+ "unicode": "2795",
+ "unicode_alternates": [],
+ "name": "heavy plus sign",
+ "shortname": ":heavy_plus_sign:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["calculation", "math"],
+ "moji": "➕"
+ },
+ "helicopter": {
+ "unicode": "1F681",
+ "unicode_alternates": [],
+ "name": "helicopter",
+ "shortname": ":helicopter:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "helicopter", "helo", "gyro", "gyrocopter"],
+ "moji": "🚁"
+ },
+ "herb": {
+ "unicode": "1F33F",
+ "unicode_alternates": [],
+ "name": "herb",
+ "shortname": ":herb:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["grass", "lawn", "medicine", "plant", "vegetable", "weed", "herb", "spice", "plant", "cook", "cooking"],
+ "moji": "🌿"
+ },
+ "hibiscus": {
+ "unicode": "1F33A",
+ "unicode_alternates": [],
+ "name": "hibiscus",
+ "shortname": ":hibiscus:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flowers", "plant", "vegetable", "hibiscus", "flower", "warm"],
+ "moji": "🌺"
+ },
+ "high_brightness": {
+ "unicode": "1F506",
+ "unicode_alternates": [],
+ "name": "high brightness symbol",
+ "shortname": ":high_brightness:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["light", "summer", "sun"],
+ "moji": "🔆"
+ },
+ "high_heel": {
+ "unicode": "1F460",
+ "unicode_alternates": [],
+ "name": "high-heeled shoe",
+ "shortname": ":high_heel:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "female", "shoes"],
+ "moji": "👠"
+ },
+ "hole": {
+ "unicode": "1F573",
+ "unicode_alternates": [],
+ "name": "hole",
+ "shortname": ":hole:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["pit", "well"]
+ },
+ "homes": {
+ "unicode": "1F3D8",
+ "unicode_alternates": [],
+ "name": "house buildings",
+ "shortname": ":homes:",
+ "category": "travel_places",
+ "aliases": [":house_buildings:"],
+ "aliases_ascii": [],
+ "keywords": ["home", "residence", "dwelling", "mansion", "bungalow", "ranch", "craftsman"]
+ },
+ "honey_pot": {
+ "unicode": "1F36F",
+ "unicode_alternates": [],
+ "name": "honey pot",
+ "shortname": ":honey_pot:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bees", "sweet", "honey", "pot", "bees", "pooh", "bear"],
+ "moji": "🍯"
+ },
+ "horse": {
+ "unicode": "1F434",
+ "unicode_alternates": [],
+ "name": "horse face",
+ "shortname": ":horse:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "brown"],
+ "moji": "🐴"
+ },
+ "horse_racing": {
+ "unicode": "1F3C7",
+ "unicode_alternates": [],
+ "name": "horse racing",
+ "shortname": ":horse_racing:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "betting", "competition", "horse", "race", "racing", "jockey", "triple crown"],
+ "moji": "🏇"
+ },
+ "hospital": {
+ "unicode": "1F3E5",
+ "unicode_alternates": [],
+ "name": "hospital",
+ "shortname": ":hospital:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "doctor", "health", "surgery"],
+ "moji": "🏥"
+ },
+ "hot_pepper": {
+ "unicode": "1F336",
+ "unicode_alternates": [],
+ "name": "hot pepper",
+ "shortname": ":hot_pepper:",
+ "category": "food_drink",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "nature", "spicy", "chili", "cayenne", "habanero", "jalapeno"]
+ },
+ "hotel": {
+ "unicode": "1F3E8",
+ "unicode_alternates": [],
+ "name": "hotel",
+ "shortname": ":hotel:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accomodation", "building", "checkin", "whotel", "hotel", "motel", "holiday inn", "hospital"],
+ "moji": "🏨"
+ },
+ "hotsprings": {
+ "unicode": "2668",
+ "unicode_alternates": ["2668-FE0F"],
+ "name": "hot springs",
+ "shortname": ":hotsprings:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bath", "relax", "warm"],
+ "moji": "♨"
+ },
+ "hourglass": {
+ "unicode": "231B",
+ "unicode_alternates": ["231B-FE0F"],
+ "name": "hourglass",
+ "shortname": ":hourglass:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clock", "oldschool", "time"],
+ "moji": "⌛"
+ },
+ "hourglass_flowing_sand": {
+ "unicode": "23F3",
+ "unicode_alternates": [],
+ "name": "hourglass with flowing sand",
+ "shortname": ":hourglass_flowing_sand:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["countdown", "oldschool", "time"],
+ "moji": "⏳"
+ },
+ "house": {
+ "unicode": "1F3E0",
+ "unicode_alternates": [],
+ "name": "house building",
+ "shortname": ":house:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "home", "house", "home", "residence", "dwelling", "mansion", "bungalow", "ranch", "craftsman"],
+ "moji": "🏠"
+ },
+ "house_abandoned": {
+ "unicode": "1F3DA",
+ "unicode_alternates": [],
+ "name": "derelict house building",
+ "shortname": ":house_abandoned:",
+ "category": "travel_places",
+ "aliases": [":derelict_house_building:"],
+ "aliases_ascii": [],
+ "keywords": ["home", "residence", "dwelling", "mansion", "bungalow", "ranch", "craftsman", "boarded", "abandoned", "vacant", "run down", "shoddy"]
+ },
+ "house_with_garden": {
+ "unicode": "1F3E1",
+ "unicode_alternates": [],
+ "name": "house with garden",
+ "shortname": ":house_with_garden:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["home", "nature", "plant"],
+ "moji": "🏡"
+ },
+ "hushed": {
+ "unicode": "1F62F",
+ "unicode_alternates": [],
+ "name": "hushed face",
+ "shortname": ":hushed:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "woo", "quiet", "hush", "whisper", "silent"],
+ "moji": "😯"
+ },
+ "ice_cream": {
+ "unicode": "1F368",
+ "unicode_alternates": [],
+ "name": "ice cream",
+ "shortname": ":ice_cream:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "hot", "icecream", "ice", "cream", "dairy", "dessert", "cold", "soft", "serve", "cone", "waffle"],
+ "moji": "🍨"
+ },
+ "icecream": {
+ "unicode": "1F366",
+ "unicode_alternates": [],
+ "name": "soft ice cream",
+ "shortname": ":icecream:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "food", "hot", "icecream", "ice", "cream", "dairy", "dessert", "cold", "soft", "serve", "cone", "yogurt"],
+ "moji": "🍦"
+ },
+ "ideograph_advantage": {
+ "unicode": "1F250",
+ "unicode_alternates": [],
+ "name": "circled ideograph advantage",
+ "shortname": ":ideograph_advantage:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "get", "kanji", "obtain"],
+ "moji": "🉐"
+ },
+ "imp": {
+ "unicode": "1F47F",
+ "unicode_alternates": [],
+ "name": "imp",
+ "shortname": ":imp:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["angry", "devil", "evil", "horns", "cute", "devil"],
+ "moji": "👿"
+ },
+ "inbox_tray": {
+ "unicode": "1F4E5",
+ "unicode_alternates": [],
+ "name": "inbox tray",
+ "shortname": ":inbox_tray:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents", "email"],
+ "moji": "📥"
+ },
+ "incoming_envelope": {
+ "unicode": "1F4E8",
+ "unicode_alternates": [],
+ "name": "incoming envelope",
+ "shortname": ":incoming_envelope:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["email", "inbox"],
+ "moji": "📨"
+ },
+ "info": {
+ "unicode": "1F6C8",
+ "unicode_alternates": [],
+ "name": "circled information source",
+ "shortname": ":info:",
+ "category": "objects_symbols",
+ "aliases": [":circled_information_source:"],
+ "aliases_ascii": [],
+ "keywords": ["icon"]
+ },
+ "information_desk_person": {
+ "unicode": "1F481",
+ "unicode_alternates": [],
+ "name": "information desk person",
+ "shortname": ":information_desk_person:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "human", "woman", "information", "help", "question", "answer", "sassy", "unimpressed", "attitude", "snarky"],
+ "moji": "💁"
+ },
+ "information_source": {
+ "unicode": "2139",
+ "unicode_alternates": ["2139-FE0F"],
+ "name": "information source",
+ "shortname": ":information_source:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-square", "letter"],
+ "moji": "ℹ"
+ },
+ "innocent": {
+ "unicode": "1F607",
+ "unicode_alternates": [],
+ "name": "smiling face with halo",
+ "shortname": ":innocent:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["O:-)", "0:-3", "0:3", "0:-)", "0:)", "0;^)", "O:-)", "O:)", "O;-)", "O=)", "0;-)", "O:-3", "O:3"],
+ "keywords": ["angel", "face", "halo", "halo", "angel", "innocent", "ring", "circle", "heaven"],
+ "moji": "😇"
+ },
+ "interrobang": {
+ "unicode": "2049",
+ "unicode_alternates": ["2049-FE0F"],
+ "name": "exclamation question mark",
+ "shortname": ":interrobang:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["punctuation", "surprise", "wat"],
+ "moji": "⁉"
+ },
+ "iphone": {
+ "unicode": "1F4F1",
+ "unicode_alternates": [],
+ "name": "mobile phone",
+ "shortname": ":iphone:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["apple", "dial", "gadgets", "technology"],
+ "moji": "📱"
+ },
+ "island": {
+ "unicode": "1F3DD",
+ "unicode_alternates": [],
+ "name": "desert island",
+ "shortname": ":island:",
+ "category": "travel_places",
+ "aliases": [":desert_island:"],
+ "aliases_ascii": [],
+ "keywords": ["land", "solitude", "alone"]
+ },
+ "izakaya_lantern": {
+ "unicode": "1F3EE",
+ "unicode_alternates": [],
+ "name": "izakaya lantern",
+ "shortname": ":izakaya_lantern:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["light", "izakaya", "lantern", "stay", "drink", "alcohol", "bar", "sake", "restaurant"],
+ "moji": "🏮"
+ },
+ "jack_o_lantern": {
+ "unicode": "1F383",
+ "unicode_alternates": [],
+ "name": "jack-o-lantern",
+ "shortname": ":jack_o_lantern:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["halloween", "jack-o-lantern", "pumpkin", "halloween", "holiday", "carve", "autumn", "fall", "october", "saints", "costume", "spooky", "horror", "scary", "scared", "dead"],
+ "moji": "🎃"
+ },
+ "japan": {
+ "unicode": "1F5FE",
+ "unicode_alternates": [],
+ "name": "silhouette of japan",
+ "shortname": ":japan:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nation"],
+ "moji": "🗾"
+ },
+ "japanese_castle": {
+ "unicode": "1F3EF",
+ "unicode_alternates": [],
+ "name": "japanese castle",
+ "shortname": ":japanese_castle:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "photo", "castle", "japanese", "residence", "royalty", "fort", "fortified", "fortress"],
+ "moji": "🏯"
+ },
+ "japanese_goblin": {
+ "unicode": "1F47A",
+ "unicode_alternates": [],
+ "name": "japanese goblin",
+ "shortname": ":japanese_goblin:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["evil", "mask", "red", "japanese", "tengu", "supernatural", "avian", "demon", "goblin", "mask", "theater", "nose", "frown", "mustache", "anger", "frustration"],
+ "moji": "👺"
+ },
+ "japanese_ogre": {
+ "unicode": "1F479",
+ "unicode_alternates": [],
+ "name": "japanese ogre",
+ "shortname": ":japanese_ogre:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["monster", "japanese", "oni", "demon", "troll", "ogre", "folklore", "monster", "devil", "mask", "theater", "horns", "teeth"],
+ "moji": "👹"
+ },
+ "jeans": {
+ "unicode": "1F456",
+ "unicode_alternates": [],
+ "name": "jeans",
+ "shortname": ":jeans:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "shopping", "jeans", "pants", "blue", "denim", "levi&#039;s", "levi", "designer", "work", "skinny"],
+ "moji": "👖"
+ },
+ "jet_up": {
+ "unicode": "1F6E6",
+ "unicode_alternates": [],
+ "name": "up-pointing military airplane",
+ "shortname": ":jet_up:",
+ "category": "travel_places",
+ "aliases": [":up_pointing_military_airplane:"],
+ "aliases_ascii": [],
+ "keywords": ["jet"]
+ },
+ "joy": {
+ "unicode": "1F602",
+ "unicode_alternates": [],
+ "name": "face with tears of joy",
+ "shortname": ":joy:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":')", ":'-)"],
+ "keywords": ["cry", "face", "haha", "happy", "tears", "tears", "cry", "joy", "happy", "weep"],
+ "moji": "😂"
+ },
+ "joy_cat": {
+ "unicode": "1F639",
+ "unicode_alternates": [],
+ "name": "cat face with tears of joy",
+ "shortname": ":joy_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "haha", "happy", "tears", "happy", "tears", "cry", "joy"],
+ "moji": "😹"
+ },
+ "joystick": {
+ "unicode": "1F579",
+ "unicode_alternates": [],
+ "name": "joystick",
+ "shortname": ":joystick:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["games", "atari", "controller"]
+ },
+ "key": {
+ "unicode": "1F511",
+ "unicode_alternates": [],
+ "name": "key",
+ "shortname": ":key:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["door", "lock", "password"],
+ "moji": "🔑"
+ },
+ "key2": {
+ "unicode": "1F5DD",
+ "unicode_alternates": [],
+ "name": "old key",
+ "shortname": ":key2:",
+ "category": "objects_symbols",
+ "aliases": [":old_key:"],
+ "aliases_ascii": [],
+ "keywords": ["door", "lock", "password", "skeleton"]
+ },
+ "keyboard": {
+ "unicode": "1F5AE",
+ "unicode_alternates": [],
+ "name": "wired keyboard",
+ "shortname": ":keyboard:",
+ "category": "objects_symbols",
+ "aliases": [":wired_keyboard:"],
+ "aliases_ascii": [],
+ "keywords": ["typing", "keys", "input", "device"]
+ },
+ "keyboard_mouse": {
+ "unicode": "1F5A6",
+ "unicode_alternates": [],
+ "name": "keyboard and mouse",
+ "shortname": ":keyboard_mouse:",
+ "category": "objects_symbols",
+ "aliases": [":keyboard_and_mouse:"],
+ "aliases_ascii": [],
+ "keywords": ["computer", "input", "desktop"]
+ },
+ "keyboard_with_jacks": {
+ "unicode": "1F398",
+ "unicode_alternates": [],
+ "name": "musical keyboard with jacks",
+ "shortname": ":keyboard_with_jacks:",
+ "category": "objects_symbols",
+ "aliases": [":musical_keyboard_with_jacks:"],
+ "aliases_ascii": [],
+ "keywords": ["music", "instrument", "midi"]
+ },
+ "keycap_ten": {
+ "unicode": "1F51F",
+ "unicode_alternates": [],
+ "name": "keycap ten",
+ "shortname": ":keycap_ten:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["10", "blue-square", "numbers"],
+ "moji": "🔟"
+ },
+ "kimono": {
+ "unicode": "1F458",
+ "unicode_alternates": [],
+ "name": "kimono",
+ "shortname": ":kimono:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["dress", "fashion", "female", "japanese", "women"],
+ "moji": "👘"
+ },
+ "kiss": {
+ "unicode": "1F48B",
+ "unicode_alternates": [],
+ "name": "kiss mark",
+ "shortname": ":kiss:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "face", "like", "lips", "love", "valentines"],
+ "moji": "💋"
+ },
+ "kiss_mm": {
+ "unicode": "1F468-2764-1F48B-1F468",
+ "unicode_alternates": ["1F468-200D-2764-FE0F-200D-1F48B-200D-1F468"],
+ "name": "kiss (man,man)",
+ "shortname": ":kiss_mm:",
+ "category": "people",
+ "aliases": [":couplekiss_mm:"],
+ "aliases_ascii": [],
+ "keywords": ["dating", "like", "love", "marriage", "valentines", "couple"]
+ },
+ "kiss_ww": {
+ "unicode": "1F469-2764-1F48B-1F469",
+ "unicode_alternates": ["1F469-200D-2764-FE0F-200D-1F48B-200D-1F469"],
+ "name": "kiss (woman,woman)",
+ "shortname": ":kiss_ww:",
+ "category": "people",
+ "aliases": [":couplekiss_ww:"],
+ "aliases_ascii": [],
+ "keywords": ["dating", "like", "love", "marriage", "valentines", "couple"]
+ },
+ "kissing": {
+ "unicode": "1F617",
+ "unicode_alternates": [],
+ "name": "kissing face",
+ "shortname": ":kissing:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["3", "face", "infatuation", "like", "love", "valentines", "kissing", "kiss", "pucker", "lips", "smooch"],
+ "moji": "😗"
+ },
+ "kissing_cat": {
+ "unicode": "1F63D",
+ "unicode_alternates": [],
+ "name": "kissing cat face with closed eyes",
+ "shortname": ":kissing_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "passion", "kiss", "puckered", "heart", "love"],
+ "moji": "😽"
+ },
+ "kissing_closed_eyes": {
+ "unicode": "1F61A",
+ "unicode_alternates": [],
+ "name": "kissing face with closed eyes",
+ "shortname": ":kissing_closed_eyes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "face", "infatuation", "like", "love", "valentines", "kissing", "kiss", "passion", "puckered", "heart", "love", "smooch"],
+ "moji": "😚"
+ },
+ "kissing_heart": {
+ "unicode": "1F618",
+ "unicode_alternates": [],
+ "name": "face throwing a kiss",
+ "shortname": ":kissing_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":*", ":-*", "=*", ":^*"],
+ "keywords": ["affection", "face", "infatuation", "kiss", "blowing kiss", "heart", "love", "lips", "like", "love", "valentines"],
+ "moji": "😘"
+ },
+ "kissing_smiling_eyes": {
+ "unicode": "1F619",
+ "unicode_alternates": [],
+ "name": "kissing face with smiling eyes",
+ "shortname": ":kissing_smiling_eyes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "face", "infatuation", "valentines", "kissing", "kiss", "smile", "pucker", "lips", "smooch"],
+ "moji": "😙"
+ },
+ "knife": {
+ "unicode": "1F52A",
+ "unicode_alternates": [],
+ "name": "hocho",
+ "shortname": ":knife:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "🔪"
+ },
+ "koala": {
+ "unicode": "1F428",
+ "unicode_alternates": [],
+ "name": "koala",
+ "shortname": ":koala:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐨"
+ },
+ "koko": {
+ "unicode": "1F201",
+ "unicode_alternates": [],
+ "name": "squared katakana koko",
+ "shortname": ":koko:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "destination", "here", "japanese", "katakana"],
+ "moji": "🈁"
+ },
+ "label": {
+ "unicode": "1F3F7",
+ "unicode_alternates": [],
+ "name": "label",
+ "shortname": ":label:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["tag"]
+ },
+ "large_blue_circle": {
+ "unicode": "1F535",
+ "unicode_alternates": [],
+ "name": "large blue circle",
+ "shortname": ":large_blue_circle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "🔵"
+ },
+ "large_blue_diamond": {
+ "unicode": "1F537",
+ "unicode_alternates": [],
+ "name": "large blue diamond",
+ "shortname": ":large_blue_diamond:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔷"
+ },
+ "large_orange_diamond": {
+ "unicode": "1F536",
+ "unicode_alternates": [],
+ "name": "large orange diamond",
+ "shortname": ":large_orange_diamond:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔶"
+ },
+ "last_quarter_moon": {
+ "unicode": "1F317",
+ "unicode_alternates": [],
+ "name": "last quarter moon symbol",
+ "shortname": ":last_quarter_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "last", "quarter", "sky", "night", "cheese", "phase"],
+ "moji": "🌗"
+ },
+ "last_quarter_moon_with_face": {
+ "unicode": "1F31C",
+ "unicode_alternates": [],
+ "name": "last quarter moon with face",
+ "shortname": ":last_quarter_moon_with_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "last", "quarter", "anthropomorphic", "face", "sky", "night", "cheese", "phase"],
+ "moji": "🌜"
+ },
+ "laughing": {
+ "unicode": "1F606",
+ "unicode_alternates": [],
+ "name": "smiling face with open mouth and tightly-closed ey",
+ "shortname": ":laughing:",
+ "category": "emoticons",
+ "aliases": [":satisfied:"],
+ "aliases_ascii": [">:)", ">;)", ">:-)", ">=)"],
+ "keywords": ["happy", "joy", "lol", "smiling", "laughing", "laugh"],
+ "moji": "😆"
+ },
+ "leaves": {
+ "unicode": "1F343",
+ "unicode_alternates": [],
+ "name": "leaf fluttering in wind",
+ "shortname": ":leaves:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["grass", "lawn", "nature", "plant", "tree", "vegetable", "leaves", "leaf", "wind", "float", "fluttering"],
+ "moji": "🍃"
+ },
+ "ledger": {
+ "unicode": "1F4D2",
+ "unicode_alternates": [],
+ "name": "ledger",
+ "shortname": ":ledger:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["notes", "paper"],
+ "moji": "📒"
+ },
+ "left_luggage": {
+ "unicode": "1F6C5",
+ "unicode_alternates": [],
+ "name": "left luggage",
+ "shortname": ":left_luggage:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "travel", "bag", "baggage", "luggage", "travel"],
+ "moji": "🛅"
+ },
+ "left_receiver": {
+ "unicode": "1F57B",
+ "unicode_alternates": [],
+ "name": "left hand telephone receiver",
+ "shortname": ":left_receiver:",
+ "category": "objects_symbols",
+ "aliases": [":left_hand_telephone_receiver:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "dial", "technology"]
+ },
+ "left_right_arrow": {
+ "unicode": "2194",
+ "unicode_alternates": ["2194-FE0F"],
+ "name": "left right arrow",
+ "shortname": ":left_right_arrow:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "↔"
+ },
+ "leftwards_arrow_with_hook": {
+ "unicode": "21A9",
+ "unicode_alternates": ["21A9-FE0F"],
+ "name": "leftwards arrow with hook",
+ "shortname": ":leftwards_arrow_with_hook:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "↩"
+ },
+ "lemon": {
+ "unicode": "1F34B",
+ "unicode_alternates": [],
+ "name": "lemon",
+ "shortname": ":lemon:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fruit", "nature", "lemon", "yellow", "citrus"],
+ "moji": "🍋"
+ },
+ "leo": {
+ "unicode": "264C",
+ "unicode_alternates": ["264C-FE0F"],
+ "name": "leo",
+ "shortname": ":leo:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["leo", "lion", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "purple-square", "sign", "zodiac", "horoscope"],
+ "moji": "♌"
+ },
+ "leopard": {
+ "unicode": "1F406",
+ "unicode_alternates": [],
+ "name": "leopard",
+ "shortname": ":leopard:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "leopard", "cat", "spot", "spotted", "sexy"],
+ "moji": "🐆"
+ },
+ "level_slider": {
+ "unicode": "1F39A",
+ "unicode_alternates": [],
+ "name": "level slider",
+ "shortname": ":level_slider:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["controls"]
+ },
+ "levitate": {
+ "unicode": "1F574",
+ "unicode_alternates": [],
+ "name": "man in business suit levitating",
+ "shortname": ":levitate:",
+ "category": "people",
+ "aliases": [":man_in_business_suit_levitating:"],
+ "aliases_ascii": [],
+ "keywords": ["hover", "exclamation"]
+ },
+ "libra": {
+ "unicode": "264E",
+ "unicode_alternates": ["264E-FE0F"],
+ "name": "libra",
+ "shortname": ":libra:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["libra", "scales", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "purple-square", "sign", "zodiac", "horoscope"],
+ "moji": "♎"
+ },
+ "lifter": {
+ "unicode": "1F3CB",
+ "unicode_alternates": [],
+ "name": "weight lifter",
+ "shortname": ":lifter:",
+ "category": "activity",
+ "aliases": [":weight_lifter:"],
+ "aliases_ascii": [],
+ "keywords": ["bench", "press", "squats", "deadlift"]
+ },
+ "light_check_mark": {
+ "unicode": "1F5F8",
+ "unicode_alternates": [],
+ "name": "light check mark",
+ "shortname": ":light_check_mark:",
+ "category": "objects_symbols",
+ "aliases": [":light_mark:"],
+ "aliases_ascii": [],
+ "keywords": ["vote"]
+ },
+ "light_rail": {
+ "unicode": "1F688",
+ "unicode_alternates": [],
+ "name": "light rail",
+ "shortname": ":light_rail:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "train", "rail", "light"],
+ "moji": "🚈"
+ },
+ "link": {
+ "unicode": "1F517",
+ "unicode_alternates": [],
+ "name": "link symbol",
+ "shortname": ":link:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["rings", "url"],
+ "moji": "🔗"
+ },
+ "lips": {
+ "unicode": "1F444",
+ "unicode_alternates": [],
+ "name": "mouth",
+ "shortname": ":lips:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["kiss", "mouth"],
+ "moji": "👄"
+ },
+ "lips2": {
+ "unicode": "1F5E2",
+ "unicode_alternates": [],
+ "name": "lips",
+ "shortname": ":lips2:",
+ "category": "people",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["kiss", "mouth"]
+ },
+ "lipstick": {
+ "unicode": "1F484",
+ "unicode_alternates": [],
+ "name": "lipstick",
+ "shortname": ":lipstick:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "female", "girl"],
+ "moji": "💄"
+ },
+ "lock": {
+ "unicode": "1F512",
+ "unicode_alternates": [],
+ "name": "lock",
+ "shortname": ":lock:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["password", "security"],
+ "moji": "🔒"
+ },
+ "lock_with_ink_pen": {
+ "unicode": "1F50F",
+ "unicode_alternates": [],
+ "name": "lock with ink pen",
+ "shortname": ":lock_with_ink_pen:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["secret", "security"],
+ "moji": "🔏"
+ },
+ "lollipop": {
+ "unicode": "1F36D",
+ "unicode_alternates": [],
+ "name": "lollipop",
+ "shortname": ":lollipop:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["candy", "food", "snack", "sweet", "lollipop", "stick", "lick", "sweet", "sugar", "candy"],
+ "moji": "🍭"
+ },
+ "loop": {
+ "unicode": "27BF",
+ "unicode_alternates": [],
+ "name": "double curly loop",
+ "shortname": ":loop:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["curly"],
+ "moji": "➿"
+ },
+ "loud_sound": {
+ "unicode": "1F50A",
+ "unicode_alternates": [],
+ "name": "speaker with three sound waves",
+ "shortname": ":loud_sound:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": [],
+ "moji": "🔊"
+ },
+ "loudspeaker": {
+ "unicode": "1F4E2",
+ "unicode_alternates": [],
+ "name": "public address loudspeaker",
+ "shortname": ":loudspeaker:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "volume"],
+ "moji": "📢"
+ },
+ "love_hotel": {
+ "unicode": "1F3E9",
+ "unicode_alternates": [],
+ "name": "love hotel",
+ "shortname": ":love_hotel:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "dating", "like", "love", "hotel", "love", "sex", "romance", "leisure", "adultery", "prostitution", "hospital", "birth", "happy"],
+ "moji": "🏩"
+ },
+ "love_letter": {
+ "unicode": "1F48C",
+ "unicode_alternates": [],
+ "name": "love letter",
+ "shortname": ":love_letter:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "email", "envelope", "like", "valentines", "love", "letter", "kiss", "heart"],
+ "moji": "💌"
+ },
+ "low_brightness": {
+ "unicode": "1F505",
+ "unicode_alternates": [],
+ "name": "low brightness symbol",
+ "shortname": ":low_brightness:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["summer", "sun"],
+ "moji": "🔅"
+ },
+ "m": {
+ "unicode": "24C2",
+ "unicode_alternates": ["24C2-FE0F"],
+ "name": "circled latin capital letter m",
+ "shortname": ":m:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-circle", "letter"],
+ "moji": "Ⓜ"
+ },
+ "mag": {
+ "unicode": "1F50D",
+ "unicode_alternates": [],
+ "name": "left-pointing magnifying glass",
+ "shortname": ":mag:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["search", "zoom", "detective", "investigator", "detail", "details"],
+ "moji": "🔍"
+ },
+ "mag_right": {
+ "unicode": "1F50E",
+ "unicode_alternates": [],
+ "name": "right-pointing magnifying glass",
+ "shortname": ":mag_right:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["search", "zoom", "detective", "investigator", "detail", "details"],
+ "moji": "🔎"
+ },
+ "mahjong": {
+ "unicode": "1F004",
+ "unicode_alternates": ["1F004-FE0F"],
+ "name": "mahjong tile red dragon",
+ "shortname": ":mahjong:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "game", "kanji"],
+ "moji": "🀄"
+ },
+ "mailbox": {
+ "unicode": "1F4EB",
+ "unicode_alternates": [],
+ "name": "closed mailbox with raised flag",
+ "shortname": ":mailbox:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "email", "inbox"],
+ "moji": "📫"
+ },
+ "mailbox_closed": {
+ "unicode": "1F4EA",
+ "unicode_alternates": [],
+ "name": "closed mailbox with lowered flag",
+ "shortname": ":mailbox_closed:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "email", "inbox"],
+ "moji": "📪"
+ },
+ "mailbox_with_mail": {
+ "unicode": "1F4EC",
+ "unicode_alternates": [],
+ "name": "open mailbox with raised flag",
+ "shortname": ":mailbox_with_mail:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "email", "inbox"],
+ "moji": "📬"
+ },
+ "mailbox_with_no_mail": {
+ "unicode": "1F4ED",
+ "unicode_alternates": [],
+ "name": "open mailbox with lowered flag",
+ "shortname": ":mailbox_with_no_mail:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["email", "inbox"],
+ "moji": "📭"
+ },
+ "man": {
+ "unicode": "1F468",
+ "unicode_alternates": [],
+ "name": "man",
+ "shortname": ":man:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["classy", "dad", "father", "guy", "mustashe"],
+ "moji": "👨"
+ },
+ "man_with_gua_pi_mao": {
+ "unicode": "1F472",
+ "unicode_alternates": [],
+ "name": "man with gua pi mao",
+ "shortname": ":man_with_gua_pi_mao:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["boy", "male", "skullcap", "chinese", "asian", "qing"],
+ "moji": "👲"
+ },
+ "man_with_turban": {
+ "unicode": "1F473",
+ "unicode_alternates": [],
+ "name": "man with turban",
+ "shortname": ":man_with_turban:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["male", "turban", "headdress", "headwear", "pagri", "india", "indian", "mummy", "wisdom", "peace"],
+ "moji": "👳"
+ },
+ "mans_shoe": {
+ "unicode": "1F45E",
+ "unicode_alternates": [],
+ "name": "mans shoe",
+ "shortname": ":mans_shoe:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "male"],
+ "moji": "👞"
+ },
+ "map": {
+ "unicode": "1F5FA",
+ "unicode_alternates": [],
+ "name": "world map",
+ "shortname": ":map:",
+ "category": "travel_places",
+ "aliases": [":world_map:"],
+ "aliases_ascii": [],
+ "keywords": ["atlas", "earth", "cartography"]
+ },
+ "maple_leaf": {
+ "unicode": "1F341",
+ "unicode_alternates": [],
+ "name": "maple leaf",
+ "shortname": ":maple_leaf:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["canada", "nature", "plant", "vegetable", "maple", "leaf", "syrup", "canada", "tree"],
+ "moji": "🍁"
+ },
+ "mask": {
+ "unicode": "1F637",
+ "unicode_alternates": [],
+ "name": "face with medical mask",
+ "shortname": ":mask:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "ill", "sick", "sick", "virus", "flu", "medical", "mask"],
+ "moji": "😷"
+ },
+ "massage": {
+ "unicode": "1F486",
+ "unicode_alternates": [],
+ "name": "face massage",
+ "shortname": ":massage:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman"],
+ "moji": "💆"
+ },
+ "meat_on_bone": {
+ "unicode": "1F356",
+ "unicode_alternates": [],
+ "name": "meat on bone",
+ "shortname": ":meat_on_bone:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "good", "meat", "bone", "animal", "cooked"],
+ "moji": "🍖"
+ },
+ "medal": {
+ "unicode": "1F3C5",
+ "unicode_alternates": [],
+ "name": "sports medal",
+ "shortname": ":medal:",
+ "category": "activity",
+ "aliases": [":sports_medal:"],
+ "aliases_ascii": [],
+ "keywords": ["award", "ceremony", "contest", "ftw", "place", "win", "first", "show", "reward", "achievement"]
+ },
+ "mega": {
+ "unicode": "1F4E3",
+ "unicode_alternates": [],
+ "name": "cheering megaphone",
+ "shortname": ":mega:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "speaker", "volume"],
+ "moji": "📣"
+ },
+ "melon": {
+ "unicode": "1F348",
+ "unicode_alternates": [],
+ "name": "melon",
+ "shortname": ":melon:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "melon", "cantaloupe", "honeydew"],
+ "moji": "🍈"
+ },
+ "mens": {
+ "unicode": "1F6B9",
+ "unicode_alternates": [],
+ "name": "mens symbol",
+ "shortname": ":mens:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["restroom", "toilet", "wc", "men", "bathroom", "restroom", "sign", "boy", "male", "avatar"],
+ "moji": "🚹"
+ },
+ "metro": {
+ "unicode": "1F687",
+ "unicode_alternates": [],
+ "name": "metro",
+ "shortname": ":metro:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "mrt", "transportation", "tube", "underground", "metro", "subway", "underground", "train"],
+ "moji": "🚇"
+ },
+ "microphone": {
+ "unicode": "1F3A4",
+ "unicode_alternates": [],
+ "name": "microphone",
+ "shortname": ":microphone:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["PA", "music", "sound", "microphone", "mic", "audio", "sound", "voice", "karaoke"],
+ "moji": "🎤"
+ },
+ "microphone2": {
+ "unicode": "1F399",
+ "unicode_alternates": [],
+ "name": "studio microphone",
+ "shortname": ":microphone2:",
+ "category": "objects_symbols",
+ "aliases": [":studio_microphone:"],
+ "aliases_ascii": [],
+ "keywords": ["mic", "audio", "recording"]
+ },
+ "microscope": {
+ "unicode": "1F52C",
+ "unicode_alternates": [],
+ "name": "microscope",
+ "shortname": ":microscope:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["experiment", "laboratory", "zoomin"],
+ "moji": "🔬"
+ },
+ "middle_finger": {
+ "unicode": "1F595",
+ "unicode_alternates": [],
+ "name": "reversed hand with middle finger extended",
+ "shortname": ":middle_finger:",
+ "category": "people",
+ "aliases": [":reversed_hand_with_middle_finger_extended:"],
+ "aliases_ascii": [],
+ "keywords": ["fu"]
+ },
+ "military_medal": {
+ "unicode": "1F396",
+ "unicode_alternates": [],
+ "name": "military medal",
+ "shortname": ":military_medal:",
+ "category": "celebration",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["honor", "acknowledgment", "purple heart", "heroism", "veteran"]
+ },
+ "milky_way": {
+ "unicode": "1F30C",
+ "unicode_alternates": [],
+ "name": "milky way",
+ "shortname": ":milky_way:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "space", "milky", "galaxy", "star", "stars", "planets", "space", "sky"],
+ "moji": "🌌"
+ },
+ "minibus": {
+ "unicode": "1F690",
+ "unicode_alternates": [],
+ "name": "minibus",
+ "shortname": ":minibus:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["car", "transportation", "vehicle", "bus", "city", "transport", "transportation"],
+ "moji": "🚐"
+ },
+ "minidisc": {
+ "unicode": "1F4BD",
+ "unicode_alternates": [],
+ "name": "minidisc",
+ "shortname": ":minidisc:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["data", "disc", "disk", "record", "technology"],
+ "moji": "💽"
+ },
+ "mobile_phone_off": {
+ "unicode": "1F4F4",
+ "unicode_alternates": [],
+ "name": "mobile phone off",
+ "shortname": ":mobile_phone_off:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mute"],
+ "moji": "📴"
+ },
+ "money_with_wings": {
+ "unicode": "1F4B8",
+ "unicode_alternates": [],
+ "name": "money with wings",
+ "shortname": ":money_with_wings:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bills", "dollar", "payment", "money", "wings", "easy", "spend", "work", "lost", "blown", "burned", "gift", "cash", "dollar"],
+ "moji": "💸"
+ },
+ "moneybag": {
+ "unicode": "1F4B0",
+ "unicode_alternates": [],
+ "name": "money bag",
+ "shortname": ":moneybag:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["coins", "dollar", "payment"],
+ "moji": "💰"
+ },
+ "monkey": {
+ "unicode": "1F412",
+ "unicode_alternates": [],
+ "name": "monkey",
+ "shortname": ":monkey:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "monkey", "primate", "banana", "silly"],
+ "moji": "🐒"
+ },
+ "monkey_face": {
+ "unicode": "1F435",
+ "unicode_alternates": [],
+ "name": "monkey face",
+ "shortname": ":monkey_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐵"
+ },
+ "monorail": {
+ "unicode": "1F69D",
+ "unicode_alternates": [],
+ "name": "monorail",
+ "shortname": ":monorail:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "train", "mono", "rail", "transport"],
+ "moji": "🚝"
+ },
+ "mood_bubble": {
+ "unicode": "1F5F0",
+ "unicode_alternates": [],
+ "name": "mood bubble",
+ "shortname": ":mood_bubble:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "conversation", "communication", "comic", "feeling"]
+ },
+ "mood_bubble_lightning": {
+ "unicode": "1F5F1",
+ "unicode_alternates": [],
+ "name": "lightning mood bubble",
+ "shortname": ":mood_bubble_lightning:",
+ "category": "objects_symbols",
+ "aliases": [":lightning_mood_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "conversation", "communication", "comic", "feeling"]
+ },
+ "mood_lightning": {
+ "unicode": "1F5F2",
+ "unicode_alternates": [],
+ "name": "lightning mood",
+ "shortname": ":mood_lightning:",
+ "category": "objects_symbols",
+ "aliases": [":lightning_mood:"],
+ "aliases_ascii": [],
+ "keywords": ["zap", "electric", "current"]
+ },
+ "mortar_board": {
+ "unicode": "1F393",
+ "unicode_alternates": [],
+ "name": "graduation cap",
+ "shortname": ":mortar_board:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cap", "college", "degree", "graduation", "hat", "school", "university", "graduation", "cap", "mortarboard", "academic", "education", "ceremony", "square", "tassel"],
+ "moji": "🎓"
+ },
+ "motorboat": {
+ "unicode": "1F6E5",
+ "unicode_alternates": [],
+ "name": "motorboat",
+ "shortname": ":motorboat:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "boat", "speedboat", "powerboat"]
+ },
+ "motorcycle": {
+ "unicode": "1F3CD",
+ "unicode_alternates": [],
+ "name": "racing motorcycle",
+ "shortname": ":motorcycle:",
+ "category": "activity",
+ "aliases": [":racing_motorcycle:"],
+ "aliases_ascii": [],
+ "keywords": ["bike", "speed"]
+ },
+ "motorway": {
+ "unicode": "1F6E3",
+ "unicode_alternates": [],
+ "name": "motorway",
+ "shortname": ":motorway:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["road", "highway", "freeway", "traffic", "travel"]
+ },
+ "mount_fuji": {
+ "unicode": "1F5FB",
+ "unicode_alternates": [],
+ "name": "mount fuji",
+ "shortname": ":mount_fuji:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japan", "mountain", "nature", "photo"],
+ "moji": "🗻"
+ },
+ "mountain_bicyclist": {
+ "unicode": "1F6B5",
+ "unicode_alternates": [],
+ "name": "mountain bicyclist",
+ "shortname": ":mountain_bicyclist:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["human", "sports", "transportation", "bicyclist", "mountain", "bike", "pedal", "bicycle", "transportation"],
+ "moji": "🚵"
+ },
+ "mountain_cableway": {
+ "unicode": "1F6A0",
+ "unicode_alternates": [],
+ "name": "mountain cableway",
+ "shortname": ":mountain_cableway:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "mountain", "cable", "rail", "train", "railway"],
+ "moji": "🚠"
+ },
+ "mountain_railway": {
+ "unicode": "1F69E",
+ "unicode_alternates": [],
+ "name": "mountain railway",
+ "shortname": ":mountain_railway:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "mountain", "railway", "rail", "train", "transport"],
+ "moji": "🚞"
+ },
+ "mountain_snow": {
+ "unicode": "1F3D4",
+ "unicode_alternates": [],
+ "name": "snow capped mountain",
+ "shortname": ":mountain_snow:",
+ "category": "travel_places",
+ "aliases": [":snow_capped_mountain:"],
+ "aliases_ascii": [],
+ "keywords": ["cold", "elevation", "hiking", "peak"]
+ },
+ "mouse": {
+ "unicode": "1F42D",
+ "unicode_alternates": [],
+ "name": "mouse face",
+ "shortname": ":mouse:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐭"
+ },
+ "mouse2": {
+ "unicode": "1F401",
+ "unicode_alternates": [],
+ "name": "mouse",
+ "shortname": ":mouse2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "mouse", "mice", "rodent"],
+ "moji": "🐁"
+ },
+ "mouse_one": {
+ "unicode": "1F5AF",
+ "unicode_alternates": [],
+ "name": "one button mouse",
+ "shortname": ":mouse_one:",
+ "category": "objects_symbols",
+ "aliases": [":one_button_mouse:"],
+ "aliases_ascii": [],
+ "keywords": ["computer", "input", "device"]
+ },
+ "movie_camera": {
+ "unicode": "1F3A5",
+ "unicode_alternates": [],
+ "name": "movie camera",
+ "shortname": ":movie_camera:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["film", "record", "movie", "camera", "camcorder", "video", "motion", "picture"],
+ "moji": "🎥"
+ },
+ "moyai": {
+ "unicode": "1F5FF",
+ "unicode_alternates": [],
+ "name": "moyai",
+ "shortname": ":moyai:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["island", "stone"],
+ "moji": "🗿"
+ },
+ "muscle": {
+ "unicode": "1F4AA",
+ "unicode_alternates": [],
+ "name": "flexed biceps",
+ "shortname": ":muscle:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arm", "flex", "hand", "strong", "muscle", "bicep"],
+ "moji": "💪"
+ },
+ "mushroom": {
+ "unicode": "1F344",
+ "unicode_alternates": [],
+ "name": "mushroom",
+ "shortname": ":mushroom:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["plant", "vegetable", "mushroom", "fungi", "food", "fungus"],
+ "moji": "🍄"
+ },
+ "musical_keyboard": {
+ "unicode": "1F3B9",
+ "unicode_alternates": [],
+ "name": "musical keyboard",
+ "shortname": ":musical_keyboard:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["instrument", "piano", "music", "keyboard", "piano", "organ", "instrument", "electric"],
+ "moji": "🎹"
+ },
+ "musical_note": {
+ "unicode": "1F3B5",
+ "unicode_alternates": [],
+ "name": "musical note",
+ "shortname": ":musical_note:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["score", "musical", "music", "note", "music", "sound"],
+ "moji": "🎵"
+ },
+ "musical_score": {
+ "unicode": "1F3BC",
+ "unicode_alternates": [],
+ "name": "musical score",
+ "shortname": ":musical_score:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["clef", "treble", "music", "musical", "score", "clef", "g-clef", "stave", "staff"],
+ "moji": "🎼"
+ },
+ "mute": {
+ "unicode": "1F507",
+ "unicode_alternates": [],
+ "name": "speaker with cancellation stroke",
+ "shortname": ":mute:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "volume"],
+ "moji": "🔇"
+ },
+ "nail_care": {
+ "unicode": "1F485",
+ "unicode_alternates": [],
+ "name": "nail polish",
+ "shortname": ":nail_care:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beauty", "manicure"],
+ "moji": "💅"
+ },
+ "name_badge": {
+ "unicode": "1F4DB",
+ "unicode_alternates": [],
+ "name": "name badge",
+ "shortname": ":name_badge:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fire", "forbid"],
+ "moji": "📛"
+ },
+ "necktie": {
+ "unicode": "1F454",
+ "unicode_alternates": [],
+ "name": "necktie",
+ "shortname": ":necktie:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cloth", "fashion", "formal", "shirt", "suitup"],
+ "moji": "👔"
+ },
+ "negative_squared_cross_mark": {
+ "unicode": "274E",
+ "unicode_alternates": [],
+ "name": "negative squared cross mark",
+ "shortname": ":negative_squared_cross_mark:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["deny", "green-square", "no", "x"],
+ "moji": "❎"
+ },
+ "network": {
+ "unicode": "1F5A7",
+ "unicode_alternates": [],
+ "name": "three networked computers",
+ "shortname": ":network:",
+ "category": "objects_symbols",
+ "aliases": [":three_networked_computers:"],
+ "aliases_ascii": [],
+ "keywords": ["lan", "wan", "network", "technology"]
+ },
+ "neutral_face": {
+ "unicode": "1F610",
+ "unicode_alternates": [],
+ "name": "neutral face",
+ "shortname": ":neutral_face:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "indifference", "neutral", "objective", "impartial", "blank"],
+ "moji": "😐"
+ },
+ "new": {
+ "unicode": "1F195",
+ "unicode_alternates": [],
+ "name": "squared new",
+ "shortname": ":new:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "🆕"
+ },
+ "new_moon": {
+ "unicode": "1F311",
+ "unicode_alternates": [],
+ "name": "new moon symbol",
+ "shortname": ":new_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "new", "sky", "night", "cheese", "phase"],
+ "moji": "🌑"
+ },
+ "new_moon_with_face": {
+ "unicode": "1F31A",
+ "unicode_alternates": [],
+ "name": "new moon with face",
+ "shortname": ":new_moon_with_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "new", "anthropomorphic", "face", "sky", "night", "cheese", "phase"],
+ "moji": "🌚"
+ },
+ "newspaper": {
+ "unicode": "1F4F0",
+ "unicode_alternates": [],
+ "name": "newspaper",
+ "shortname": ":newspaper:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["headline", "press"],
+ "moji": "📰"
+ },
+ "newspaper2": {
+ "unicode": "1F5DE",
+ "unicode_alternates": [],
+ "name": "rolled-up newspaper",
+ "shortname": ":newspaper2:",
+ "category": "objects_symbols",
+ "aliases": [":rolled_up_newspaper:"],
+ "aliases_ascii": [],
+ "keywords": ["headline", "press"]
+ },
+ "night_with_stars": {
+ "unicode": "1F303",
+ "unicode_alternates": [],
+ "name": "night with stars",
+ "shortname": ":night_with_stars:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "star", "cloudless", "evening", "planets", "space", "sky"],
+ "moji": "🌃"
+ },
+ "nine": {
+ "moji": "9️⃣",
+ "unicode": "0039-20E3",
+ "unicode_alternates": ["0039-FE0F-20E3"],
+ "name": "digit nine",
+ "shortname": ":nine:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["9", "blue-square", "numbers"]
+ },
+ "no_bell": {
+ "unicode": "1F515",
+ "unicode_alternates": [],
+ "name": "bell with cancellation stroke",
+ "shortname": ":no_bell:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mute", "sound", "volume"],
+ "moji": "🔕"
+ },
+ "no_bicycles": {
+ "unicode": "1F6B3",
+ "unicode_alternates": [],
+ "name": "no bicycles",
+ "shortname": ":no_bicycles:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cyclist", "prohibited", "bicycle", "bike pedal", "no"],
+ "moji": "🚳"
+ },
+ "no_entry": {
+ "unicode": "26D4",
+ "unicode_alternates": ["26D4-FE0F"],
+ "name": "no entry",
+ "shortname": ":no_entry:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bad", "denied", "limit", "privacy", "security", "stop"],
+ "moji": "⛔"
+ },
+ "no_entry_sign": {
+ "unicode": "1F6AB",
+ "unicode_alternates": [],
+ "name": "no entry sign",
+ "shortname": ":no_entry_sign:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["denied", "disallow", "forbid", "limit", "stop", "no", "stop", "entry"],
+ "moji": "🚫"
+ },
+ "no_good": {
+ "unicode": "1F645",
+ "unicode_alternates": [],
+ "name": "face with no good gesture",
+ "shortname": ":no_good:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman", "no", "stop", "nope", "don&#039;t", "not"],
+ "moji": "🙅"
+ },
+ "no_mobile_phones": {
+ "unicode": "1F4F5",
+ "unicode_alternates": [],
+ "name": "no mobile phones",
+ "shortname": ":no_mobile_phones:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["iphone", "mute"],
+ "moji": "📵"
+ },
+ "no_mouth": {
+ "unicode": "1F636",
+ "unicode_alternates": [],
+ "name": "face without mouth",
+ "shortname": ":no_mouth:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":-X", ":X", ":-#", ":#", "=X", "=x", ":x", ":-x", "=#"],
+ "keywords": ["face", "hellokitty", "mouth", "silent", "vapid"],
+ "moji": "😶"
+ },
+ "no_pedestrians": {
+ "unicode": "1F6B7",
+ "unicode_alternates": [],
+ "name": "no pedestrians",
+ "shortname": ":no_pedestrians:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["crossing", "rules", "walking", "no", "walk", "pedestrian", "stroll", "stride", "foot", "feet"],
+ "moji": "🚷"
+ },
+ "no_smoking": {
+ "unicode": "1F6AD",
+ "unicode_alternates": [],
+ "name": "no smoking symbol",
+ "shortname": ":no_smoking:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cigarette", "no", "smoking", "cigarette", "smoke", "cancer", "lungs", "inhale", "tar", "nicotine"],
+ "moji": "🚭"
+ },
+ "non-potable_water": {
+ "unicode": "1F6B1",
+ "unicode_alternates": [],
+ "name": "non-potable water symbol",
+ "shortname": ":non-potable_water:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["drink", "faucet", "tap", "non-potable", "water", "not drinkable", "dirty", "gross", "aqua", "h20"],
+ "moji": "🚱"
+ },
+ "nose": {
+ "unicode": "1F443",
+ "unicode_alternates": [],
+ "name": "nose",
+ "shortname": ":nose:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["smell", "sniff"],
+ "moji": "👃"
+ },
+ "note": {
+ "unicode": "1F5C9",
+ "unicode_alternates": [],
+ "name": "note page",
+ "shortname": ":note:",
+ "category": "objects_symbols",
+ "aliases": [":note_page:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery", "post-it"]
+ },
+ "note_empty": {
+ "unicode": "1F5C6",
+ "unicode_alternates": [],
+ "name": "empty note page",
+ "shortname": ":note_empty:",
+ "category": "objects_symbols",
+ "aliases": [":empty_note_page:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery", "post-it"]
+ },
+ "notebook": {
+ "unicode": "1F4D3",
+ "unicode_alternates": [],
+ "name": "notebook",
+ "shortname": ":notebook:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["notes", "paper", "record", "stationery"],
+ "moji": "📓"
+ },
+ "notebook_with_decorative_cover": {
+ "unicode": "1F4D4",
+ "unicode_alternates": [],
+ "name": "notebook with decorative cover",
+ "shortname": ":notebook_with_decorative_cover:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["classroom", "notes", "paper", "record"],
+ "moji": "📔"
+ },
+ "notepad": {
+ "unicode": "1F5CA",
+ "unicode_alternates": [],
+ "name": "note pad",
+ "shortname": ":notepad:",
+ "category": "objects_symbols",
+ "aliases": [":note_pad:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery", "post-it"]
+ },
+ "notepad_empty": {
+ "unicode": "1F5C7",
+ "unicode_alternates": [],
+ "name": "empty note pad",
+ "shortname": ":notepad_empty:",
+ "category": "objects_symbols",
+ "aliases": [":empty_note_pad:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery", "post-it"]
+ },
+ "notepad_spiral": {
+ "unicode": "1F5D2",
+ "unicode_alternates": [],
+ "name": "spiral note pad",
+ "shortname": ":notepad_spiral:",
+ "category": "objects_symbols",
+ "aliases": [":spiral_note_pad:"],
+ "aliases_ascii": [],
+ "keywords": ["stationery"]
+ },
+ "notes": {
+ "unicode": "1F3B6",
+ "unicode_alternates": [],
+ "name": "multiple musical notes",
+ "shortname": ":notes:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["music", "score", "musical", "music", "notes", "music", "sound", "melody"],
+ "moji": "🎶"
+ },
+ "nut_and_bolt": {
+ "unicode": "1F529",
+ "unicode_alternates": [],
+ "name": "nut and bolt",
+ "shortname": ":nut_and_bolt:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["handy", "tools"],
+ "moji": "🔩"
+ },
+ "o": {
+ "unicode": "2B55",
+ "unicode_alternates": ["2B55-FE0F"],
+ "name": "heavy large circle",
+ "shortname": ":o:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["circle", "round"],
+ "moji": "⭕"
+ },
+ "o2": {
+ "unicode": "1F17E",
+ "unicode_alternates": [],
+ "name": "negative squared latin capital letter o",
+ "shortname": ":o2:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "letter", "red-square"],
+ "moji": "🅾"
+ },
+ "ocean": {
+ "unicode": "1F30A",
+ "unicode_alternates": [],
+ "name": "water wave",
+ "shortname": ":ocean:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sea", "water", "wave", "ocean", "wave", "surf", "beach", "tide"],
+ "moji": "🌊"
+ },
+ "octopus": {
+ "unicode": "1F419",
+ "unicode_alternates": [],
+ "name": "octopus",
+ "shortname": ":octopus:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "creature", "ocean", "sea"],
+ "moji": "🐙"
+ },
+ "oden": {
+ "unicode": "1F362",
+ "unicode_alternates": [],
+ "name": "oden",
+ "shortname": ":oden:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "japanese", "oden", "seafood", "casserole", "stew"],
+ "moji": "🍢"
+ },
+ "office": {
+ "unicode": "1F3E2",
+ "unicode_alternates": [],
+ "name": "office building",
+ "shortname": ":office:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "bureau", "work"],
+ "moji": "🏢"
+ },
+ "oil": {
+ "unicode": "1F6E2",
+ "unicode_alternates": [],
+ "name": "oil drum",
+ "shortname": ":oil:",
+ "category": "objects_symbols",
+ "aliases": [":oil_drum:"],
+ "aliases_ascii": [],
+ "keywords": ["petroleum"]
+ },
+ "ok": {
+ "unicode": "1F197",
+ "unicode_alternates": [],
+ "name": "squared ok",
+ "shortname": ":ok:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["agree", "blue-square", "good", "yes"],
+ "moji": "🆗"
+ },
+ "ok_hand": {
+ "unicode": "1F44C",
+ "unicode_alternates": [],
+ "name": "ok hand sign",
+ "shortname": ":ok_hand:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fingers", "limbs", "perfect", "okay", "ok", "smoke", "smoking", "marijuana", "joint", "pot", "420"],
+ "moji": "👌"
+ },
+ "ok_woman": {
+ "unicode": "1F646",
+ "unicode_alternates": [],
+ "name": "face with ok gesture",
+ "shortname": ":ok_woman:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["*\\0/*", "\\0/", "*\\O/*", "\\O/"],
+ "keywords": ["female", "girl", "human", "pink", "women", "yes", "ok", "okay", "accept"],
+ "moji": "🙆"
+ },
+ "older_man": {
+ "unicode": "1F474",
+ "unicode_alternates": [],
+ "name": "older man",
+ "shortname": ":older_man:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["human", "male", "men"],
+ "moji": "👴"
+ },
+ "older_woman": {
+ "unicode": "1F475",
+ "unicode_alternates": [],
+ "name": "older woman",
+ "shortname": ":older_woman:",
+ "category": "emoticons",
+ "aliases": [":grandma:"],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "women", "grandma", "grandmother"],
+ "moji": "👵"
+ },
+ "om_symbol": {
+ "unicode": "1F549",
+ "unicode_alternates": [],
+ "name": "om symbol",
+ "shortname": ":om_symbol:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hinduism", "sound", "spiritual", "icon", "dharmic", "buddhism", "jainism", "meditate"]
+ },
+ "on": {
+ "unicode": "1F51B",
+ "unicode_alternates": [],
+ "name": "on with exclamation mark with left right arrow abo",
+ "shortname": ":on:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "words"],
+ "moji": "🔛"
+ },
+ "oncoming_automobile": {
+ "unicode": "1F698",
+ "unicode_alternates": [],
+ "name": "oncoming automobile",
+ "shortname": ":oncoming_automobile:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["car", "transportation", "vehicle", "sedan", "car", "automobile"],
+ "moji": "🚘"
+ },
+ "oncoming_bus": {
+ "unicode": "1F68D",
+ "unicode_alternates": [],
+ "name": "oncoming bus",
+ "shortname": ":oncoming_bus:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "bus", "school", "city", "transportation", "public"],
+ "moji": "🚍"
+ },
+ "oncoming_police_car": {
+ "unicode": "1F694",
+ "unicode_alternates": [],
+ "name": "oncoming police car",
+ "shortname": ":oncoming_police_car:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["enforcement", "law", "vehicle", "police", "car", "emergency", "ticket", "citation", "crime", "help", "officer"],
+ "moji": "🚔"
+ },
+ "oncoming_taxi": {
+ "unicode": "1F696",
+ "unicode_alternates": [],
+ "name": "oncoming taxi",
+ "shortname": ":oncoming_taxi:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "uber", "vehicle", "taxi", "car", "automobile", "city", "transport", "service"],
+ "moji": "🚖"
+ },
+ "one": {
+ "moji": "1️⃣",
+ "unicode": "0031-20E3",
+ "unicode_alternates": ["0031-FE0F-20E3"],
+ "name": "digit one",
+ "shortname": ":one:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["1", "blue-square", "numbers"]
+ },
+ "open_file_folder": {
+ "unicode": "1F4C2",
+ "unicode_alternates": [],
+ "name": "open file folder",
+ "shortname": ":open_file_folder:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents", "load"],
+ "moji": "📂"
+ },
+ "open_hands": {
+ "unicode": "1F450",
+ "unicode_alternates": [],
+ "name": "open hands sign",
+ "shortname": ":open_hands:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["butterfly", "fingers"],
+ "moji": "👐"
+ },
+ "open_mouth": {
+ "unicode": "1F62E",
+ "unicode_alternates": [],
+ "name": "face with open mouth",
+ "shortname": ":open_mouth:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":-O", ":O", ":-o", ":o", "O_O", ">:O"],
+ "keywords": ["face", "impressed", "mouth", "open", "jaw", "gapping", "surprise", "wow"],
+ "moji": "😮"
+ },
+ "ophiuchus": {
+ "unicode": "26CE",
+ "unicode_alternates": [],
+ "name": "ophiuchus",
+ "shortname": ":ophiuchus:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ophiuchus", "serpent", "snake", "astrology", "greek", "constellation", "stars", "zodiac", "purple-square", "sign", "horoscope"],
+ "moji": "⛎"
+ },
+ "optical_disk": {
+ "unicode": "1F5B8",
+ "unicode_alternates": [],
+ "name": "optical disc icon",
+ "shortname": ":optical_disk:",
+ "category": "objects_symbols",
+ "aliases": [":optical_disc_icon:"],
+ "aliases_ascii": [],
+ "keywords": ["cd", "dvd", "disc", "disk", "technology"]
+ },
+ "orange_book": {
+ "unicode": "1F4D9",
+ "unicode_alternates": [],
+ "name": "orange book",
+ "shortname": ":orange_book:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["knowledge", "library", "read"],
+ "moji": "📙"
+ },
+ "outbox_tray": {
+ "unicode": "1F4E4",
+ "unicode_alternates": [],
+ "name": "outbox tray",
+ "shortname": ":outbox_tray:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["email", "inbox"],
+ "moji": "📤"
+ },
+ "ox": {
+ "unicode": "1F402",
+ "unicode_alternates": [],
+ "name": "ox",
+ "shortname": ":ox:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "beef", "cow"],
+ "moji": "🐂"
+ },
+ "package": {
+ "unicode": "1F4E6",
+ "unicode_alternates": [],
+ "name": "package",
+ "shortname": ":package:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gift", "mail"],
+ "moji": "📦"
+ },
+ "page": {
+ "unicode": "1F5CF",
+ "unicode_alternates": [],
+ "name": "page",
+ "shortname": ":page:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["document"]
+ },
+ "page_facing_up": {
+ "unicode": "1F4C4",
+ "unicode_alternates": [],
+ "name": "page facing up",
+ "shortname": ":page_facing_up:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"],
+ "moji": "📄"
+ },
+ "page_with_curl": {
+ "unicode": "1F4C3",
+ "unicode_alternates": [],
+ "name": "page with curl",
+ "shortname": ":page_with_curl:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"],
+ "moji": "📃"
+ },
+ "pager": {
+ "unicode": "1F4DF",
+ "unicode_alternates": [],
+ "name": "pager",
+ "shortname": ":pager:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bbcall", "oldschool"],
+ "moji": "📟"
+ },
+ "pages": {
+ "unicode": "1F5D0",
+ "unicode_alternates": [],
+ "name": "pages",
+ "shortname": ":pages:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"]
+ },
+ "paintbrush": {
+ "unicode": "1F58C",
+ "unicode_alternates": [],
+ "name": "lower left paintbrush",
+ "shortname": ":paintbrush:",
+ "category": "objects_symbols",
+ "aliases": [":lower_left_paintbrush:"],
+ "aliases_ascii": [],
+ "keywords": ["brush", "art", "painting"]
+ },
+ "palm_tree": {
+ "unicode": "1F334",
+ "unicode_alternates": [],
+ "name": "palm tree",
+ "shortname": ":palm_tree:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "vegetable", "palm", "tree", "coconuts", "fronds", "warm", "tropical"],
+ "moji": "🌴"
+ },
+ "panda_face": {
+ "unicode": "1F43C",
+ "unicode_alternates": [],
+ "name": "panda face",
+ "shortname": ":panda_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "panda", "bear", "face", "cub", "cute", "endearment", "friendship", "love", "bamboo", "china", "black", "white"],
+ "moji": "🐼"
+ },
+ "paperclip": {
+ "unicode": "1F4CE",
+ "unicode_alternates": [],
+ "name": "paperclip",
+ "shortname": ":paperclip:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents", "stationery"],
+ "moji": "📎"
+ },
+ "paperclips": {
+ "unicode": "1F587",
+ "unicode_alternates": [],
+ "name": "linked paperclips",
+ "shortname": ":paperclips:",
+ "category": "objects_symbols",
+ "aliases": [":linked_paperclips:"],
+ "aliases_ascii": [],
+ "keywords": ["documents", "stationery"]
+ },
+ "park": {
+ "unicode": "1F3DE",
+ "unicode_alternates": [],
+ "name": "national park",
+ "shortname": ":park:",
+ "category": "travel_places",
+ "aliases": [":national_park:"],
+ "aliases_ascii": [],
+ "keywords": ["woods", "nature", "wildlife", "forest", "wilderness", "national"]
+ },
+ "parking": {
+ "unicode": "1F17F",
+ "unicode_alternates": ["1F17F-FE0F"],
+ "name": "negative squared latin capital letter p",
+ "shortname": ":parking:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "blue-square", "cars", "letter"],
+ "moji": "🅿"
+ },
+ "part_alternation_mark": {
+ "unicode": "303D",
+ "unicode_alternates": ["303D-FE0F"],
+ "name": "part alternation mark",
+ "shortname": ":part_alternation_mark:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph", "sing", "song", "vocal", "music", "karaoke", "cue", "letter", "m", "japanese"],
+ "moji": "〽"
+ },
+ "partly_sunny": {
+ "unicode": "26C5",
+ "unicode_alternates": ["26C5-FE0F"],
+ "name": "sun behind cloud",
+ "shortname": ":partly_sunny:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cloud", "morning", "nature", "weather"],
+ "moji": "⛅"
+ },
+ "passport_control": {
+ "unicode": "1F6C2",
+ "unicode_alternates": [],
+ "name": "passport control",
+ "shortname": ":passport_control:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "custom", "passport", "official", "travel", "control", "foreign", "identification"],
+ "moji": "🛂"
+ },
+ "peach": {
+ "unicode": "1F351",
+ "unicode_alternates": [],
+ "name": "peach",
+ "shortname": ":peach:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "peach", "fruit", "juicy", "pit"],
+ "moji": "🍑"
+ },
+ "pear": {
+ "unicode": "1F350",
+ "unicode_alternates": [],
+ "name": "pear",
+ "shortname": ":pear:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fruit", "nature", "pear", "fruit", "shape"],
+ "moji": "🍐"
+ },
+ "pen_ballpoint": {
+ "unicode": "1F58A",
+ "unicode_alternates": [],
+ "name": "lower left ballpoint pen",
+ "shortname": ":pen_ballpoint:",
+ "category": "objects_symbols",
+ "aliases": [":lower_left_ballpoint_pen:"],
+ "aliases_ascii": [],
+ "keywords": ["write", "bic", "ink"]
+ },
+ "pen_fountain": {
+ "unicode": "1F58B",
+ "unicode_alternates": [],
+ "name": "lower left fountain pen",
+ "shortname": ":pen_fountain:",
+ "category": "objects_symbols",
+ "aliases": [":lower_left_fountain_pen:"],
+ "aliases_ascii": [],
+ "keywords": ["write", "calligraphy", "ink"]
+ },
+ "pencil": {
+ "unicode": "1F4DD",
+ "unicode_alternates": [],
+ "name": "memo",
+ "shortname": ":pencil:",
+ "category": "objects",
+ "aliases": [":memo:"],
+ "aliases_ascii": [],
+ "keywords": ["documents", "paper", "station", "write"],
+ "moji": "📝"
+ },
+ "pencil2": {
+ "unicode": "270F",
+ "unicode_alternates": ["270F-FE0F"],
+ "name": "pencil",
+ "shortname": ":pencil2:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["paper", "stationery", "write"],
+ "moji": "✏"
+ },
+ "pencil3": {
+ "unicode": "1F589",
+ "unicode_alternates": [],
+ "name": "lower left pencil",
+ "shortname": ":pencil3:",
+ "category": "objects_symbols",
+ "aliases": [":lower_left_pencil:"],
+ "aliases_ascii": [],
+ "keywords": ["paper", "stationery", "write"]
+ },
+ "penguin": {
+ "unicode": "1F427",
+ "unicode_alternates": [],
+ "name": "penguin",
+ "shortname": ":penguin:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐧"
+ },
+ "pennant_black": {
+ "unicode": "1F3F2",
+ "unicode_alternates": [],
+ "name": "black pennant",
+ "shortname": ":pennant_black:",
+ "category": "objects_symbols",
+ "aliases": [":black_pennant:"],
+ "aliases_ascii": [],
+ "keywords": ["flag", "athletics"]
+ },
+ "pennant_white": {
+ "unicode": "1F3F1",
+ "unicode_alternates": [],
+ "name": "white pennant",
+ "shortname": ":pennant_white:",
+ "category": "objects_symbols",
+ "aliases": [":white_pennant:"],
+ "aliases_ascii": [],
+ "keywords": ["flag", "athletics"]
+ },
+ "pensive": {
+ "unicode": "1F614",
+ "unicode_alternates": [],
+ "name": "pensive face",
+ "shortname": ":pensive:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "okay", "sad", "pensive", "thoughtful", "think", "reflective", "wistful", "meditate", "serious"],
+ "moji": "😔"
+ },
+ "performing_arts": {
+ "unicode": "1F3AD",
+ "unicode_alternates": [],
+ "name": "performing arts",
+ "shortname": ":performing_arts:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["acting", "drama", "theater", "performing", "arts", "performance", "entertainment", "acting", "story", "mask", "masks"],
+ "moji": "🎭"
+ },
+ "persevere": {
+ "unicode": "1F623",
+ "unicode_alternates": [],
+ "name": "persevering face",
+ "shortname": ":persevere:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [">.<"],
+ "keywords": ["endure", "persevere", "face", "no", "sick", "upset"],
+ "moji": "😣"
+ },
+ "person_frowning": {
+ "unicode": "1F64D",
+ "unicode_alternates": [],
+ "name": "person frowning",
+ "shortname": ":person_frowning:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman", "dejected", "rejected", "sad", "frown"],
+ "moji": "🙍"
+ },
+ "person_with_blond_hair": {
+ "unicode": "1F471",
+ "unicode_alternates": [],
+ "name": "person with blond hair",
+ "shortname": ":person_with_blond_hair:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["male", "man", "blonde", "young", "western", "westerner", "occidental"],
+ "moji": "👱"
+ },
+ "person_with_pouting_face": {
+ "unicode": "1F64E",
+ "unicode_alternates": [],
+ "name": "person with pouting face",
+ "shortname": ":person_with_pouting_face:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman", "pout", "sexy", "cute", "annoyed"],
+ "moji": "🙎"
+ },
+ "pig": {
+ "unicode": "1F437",
+ "unicode_alternates": [],
+ "name": "pig face",
+ "shortname": ":pig:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "oink"],
+ "moji": "🐷"
+ },
+ "pig2": {
+ "unicode": "1F416",
+ "unicode_alternates": [],
+ "name": "pig",
+ "shortname": ":pig2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "pig", "piggy", "pork", "ham", "hog", "bacon", "oink", "slop", "livestock", "greed", "greedy"],
+ "moji": "🐖"
+ },
+ "pig_nose": {
+ "unicode": "1F43D",
+ "unicode_alternates": [],
+ "name": "pig nose",
+ "shortname": ":pig_nose:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "oink", "pig", "nose", "snout", "food", "eat", "cute", "oink", "pink", "smell", "truffle"],
+ "moji": "🐽"
+ },
+ "pill": {
+ "unicode": "1F48A",
+ "unicode_alternates": [],
+ "name": "pill",
+ "shortname": ":pill:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["health", "medicine"],
+ "moji": "💊"
+ },
+ "pineapple": {
+ "unicode": "1F34D",
+ "unicode_alternates": [],
+ "name": "pineapple",
+ "shortname": ":pineapple:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "pineapple", "pina", "tropical", "flower"],
+ "moji": "🍍"
+ },
+ "piracy": {
+ "unicode": "1F572",
+ "unicode_alternates": [],
+ "name": "no piracy",
+ "shortname": ":piracy:",
+ "category": "objects_symbols",
+ "aliases": [":no_piracy:"],
+ "aliases_ascii": [],
+ "keywords": ["theft", "rule"]
+ },
+ "pisces": {
+ "unicode": "2653",
+ "unicode_alternates": ["2653-FE0F"],
+ "name": "pisces",
+ "shortname": ":pisces:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["pisces", "fish", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "purple-square", "sign", "zodiac", "horoscope"],
+ "moji": "♓"
+ },
+ "pizza": {
+ "unicode": "1F355",
+ "unicode_alternates": [],
+ "name": "slice of pizza",
+ "shortname": ":pizza:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "party", "pizza", "pie", "new york", "italian", "italy", "slice", "peperoni"],
+ "moji": "🍕"
+ },
+ "point_down": {
+ "unicode": "1F447",
+ "unicode_alternates": [],
+ "name": "white down pointing backhand index",
+ "shortname": ":point_down:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["direction", "fingers", "hand"],
+ "moji": "👇"
+ },
+ "point_left": {
+ "unicode": "1F448",
+ "unicode_alternates": [],
+ "name": "white left pointing backhand index",
+ "shortname": ":point_left:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["direction", "fingers", "hand"],
+ "moji": "👈"
+ },
+ "point_right": {
+ "unicode": "1F449",
+ "unicode_alternates": [],
+ "name": "white right pointing backhand index",
+ "shortname": ":point_right:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["direction", "fingers", "hand"],
+ "moji": "👉"
+ },
+ "point_up": {
+ "unicode": "261D",
+ "unicode_alternates": ["261D-FE0F"],
+ "name": "white up pointing index",
+ "shortname": ":point_up:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["direction", "fingers", "hand"],
+ "moji": "☝"
+ },
+ "point_up_2": {
+ "unicode": "1F446",
+ "unicode_alternates": [],
+ "name": "white up pointing backhand index",
+ "shortname": ":point_up_2:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["direction", "fingers", "hand"],
+ "moji": "👆"
+ },
+ "police_car": {
+ "unicode": "1F693",
+ "unicode_alternates": [],
+ "name": "police car",
+ "shortname": ":police_car:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "enforcement", "law", "transportation", "vehicle", "police", "car", "emergency", "ticket", "citation", "crime", "help", "officer"],
+ "moji": "🚓"
+ },
+ "poodle": {
+ "unicode": "1F429",
+ "unicode_alternates": [],
+ "name": "poodle",
+ "shortname": ":poodle:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["101", "animal", "dog", "nature", "poodle", "dog", "clip", "showy", "sophisticated", "vain"],
+ "moji": "🐩"
+ },
+ "poop": {
+ "unicode": "1F4A9",
+ "unicode_alternates": [],
+ "name": "pile of poo",
+ "shortname": ":poop:",
+ "category": "emoticons",
+ "aliases": [":shit:", ":hankey:", ":poo:"],
+ "aliases_ascii": [],
+ "keywords": ["poop", "shit", "shitface", "turd", "poo"],
+ "moji": "💩"
+ },
+ "post_office": {
+ "unicode": "1F3E3",
+ "unicode_alternates": [],
+ "name": "japanese post office",
+ "shortname": ":post_office:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "communication", "email"],
+ "moji": "🏣"
+ },
+ "postal_horn": {
+ "unicode": "1F4EF",
+ "unicode_alternates": [],
+ "name": "postal horn",
+ "shortname": ":postal_horn:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["instrument", "music"],
+ "moji": "📯"
+ },
+ "postbox": {
+ "unicode": "1F4EE",
+ "unicode_alternates": [],
+ "name": "postbox",
+ "shortname": ":postbox:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["email", "envelope", "letter"],
+ "moji": "📮"
+ },
+ "potable_water": {
+ "unicode": "1F6B0",
+ "unicode_alternates": [],
+ "name": "potable water symbol",
+ "shortname": ":potable_water:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "cleaning", "faucet", "liquid", "restroom", "potable", "water", "drinkable", "pure", "clear", "clean", "aqua", "h20"],
+ "moji": "🚰"
+ },
+ "pouch": {
+ "unicode": "1F45D",
+ "unicode_alternates": [],
+ "name": "pouch",
+ "shortname": ":pouch:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "bag", "pouch", "bag", "cosmetic", "packing", "grandma", "makeup"],
+ "moji": "👝"
+ },
+ "poultry_leg": {
+ "unicode": "1F357",
+ "unicode_alternates": [],
+ "name": "poultry leg",
+ "shortname": ":poultry_leg:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "meat", "poultry", "leg", "chicken", "fried"],
+ "moji": "🍗"
+ },
+ "pound": {
+ "unicode": "1F4B7",
+ "unicode_alternates": [],
+ "name": "banknote with pound sign",
+ "shortname": ":pound:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bills", "british", "currency", "england", "money", "sterling", "uk", "pound", "britain", "british", "banknote", "money", "currency", "paper", "cash", "bills"],
+ "moji": "💷"
+ },
+ "pouting_cat": {
+ "unicode": "1F63E",
+ "unicode_alternates": [],
+ "name": "pouting cat face",
+ "shortname": ":pouting_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "pout", "annoyed", "miffed", "glower", "frown"],
+ "moji": "😾"
+ },
+ "pray": {
+ "unicode": "1F64F",
+ "unicode_alternates": [],
+ "name": "person with folded hands",
+ "shortname": ":pray:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["highfive", "hope", "namaste", "please", "wish", "pray", "high five", "hands", "sorrow", "regret", "sorry"],
+ "moji": "🙏"
+ },
+ "princess": {
+ "unicode": "1F478",
+ "unicode_alternates": [],
+ "name": "princess",
+ "shortname": ":princess:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blond", "crown", "female", "girl", "woman", "princess", "royal", "royalty", "king", "queen", "daughter", "disney", "high-maintenance"],
+ "moji": "👸"
+ },
+ "printer": {
+ "unicode": "1F5A8",
+ "unicode_alternates": [],
+ "name": "printer",
+ "shortname": ":printer:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hardcopy", "paper", "inkjet", "laser"]
+ },
+ "prohibited": {
+ "unicode": "1F6C7",
+ "unicode_alternates": [],
+ "name": "prohibited sign",
+ "shortname": ":prohibited:",
+ "category": "objects_symbols",
+ "aliases": [":prohibited_sign:"],
+ "aliases_ascii": [],
+ "keywords": ["no", "not", "denied", "disallow", "forbid", "limit", "stop"]
+ },
+ "projector": {
+ "unicode": "1F4FD",
+ "unicode_alternates": [],
+ "name": "film projector",
+ "shortname": ":projector:",
+ "category": "objects_symbols",
+ "aliases": [":film_projector:"],
+ "aliases_ascii": [],
+ "keywords": ["movie", "video", "motion", "picture", "8mm", "16mm"]
+ },
+ "punch": {
+ "unicode": "1F44A",
+ "unicode_alternates": [],
+ "name": "fisted hand sign",
+ "shortname": ":punch:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fist", "hand"],
+ "moji": "👊"
+ },
+ "purple_heart": {
+ "unicode": "1F49C",
+ "unicode_alternates": [],
+ "name": "purple heart",
+ "shortname": ":purple_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "purple", "violet", "heart", "love", "sensitive", "understanding", "compassionate", "compassion", "duty", "honor", "royalty", "veteran", "sacrifice"],
+ "moji": "💜"
+ },
+ "purse": {
+ "unicode": "1F45B",
+ "unicode_alternates": [],
+ "name": "purse",
+ "shortname": ":purse:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "fashion", "money", "purse", "clutch", "bag", "handbag", "coin bag", "accessory", "money", "ladies", "shopping"],
+ "moji": "👛"
+ },
+ "pushpin": {
+ "unicode": "1F4CC",
+ "unicode_alternates": [],
+ "name": "pushpin",
+ "shortname": ":pushpin:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["stationery"],
+ "moji": "📌"
+ },
+ "pushpin_black": {
+ "unicode": "1F588",
+ "unicode_alternates": [],
+ "name": "black pushpin",
+ "shortname": ":pushpin_black:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["stationery"]
+ },
+ "put_litter_in_its_place": {
+ "unicode": "1F6AE",
+ "unicode_alternates": [],
+ "name": "put litter in its place symbol",
+ "shortname": ":put_litter_in_its_place:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "litter", "waste", "trash", "garbage", "receptacle", "can"],
+ "moji": "🚮"
+ },
+ "question": {
+ "unicode": "2753",
+ "unicode_alternates": [],
+ "name": "black question mark ornament",
+ "shortname": ":question:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["confused", "doubt"],
+ "moji": "❓"
+ },
+ "rabbit": {
+ "unicode": "1F430",
+ "unicode_alternates": [],
+ "name": "rabbit face",
+ "shortname": ":rabbit:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐰"
+ },
+ "rabbit2": {
+ "unicode": "1F407",
+ "unicode_alternates": [],
+ "name": "rabbit",
+ "shortname": ":rabbit2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "rabbit", "bunny", "easter", "reproduction", "prolific"],
+ "moji": "🐇"
+ },
+ "race_car": {
+ "unicode": "1F3CE",
+ "unicode_alternates": [],
+ "name": "racing car",
+ "shortname": ":race_car:",
+ "category": "activity",
+ "aliases": [":racing_car:"],
+ "aliases_ascii": [],
+ "keywords": ["formula 1", "race", "stock", "nascar", "speed", "drive"]
+ },
+ "racehorse": {
+ "unicode": "1F40E",
+ "unicode_alternates": [],
+ "name": "horse",
+ "shortname": ":racehorse:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "gamble", "horse", "powerful", "draft", "calvary", "cowboy", "cowgirl", "mounted", "race", "ride", "gallop", "trot", "colt", "filly", "mare", "stallion", "gelding", "yearling", "thoroughbred", "pony"],
+ "moji": "🐎"
+ },
+ "radio": {
+ "unicode": "1F4FB",
+ "unicode_alternates": [],
+ "name": "radio",
+ "shortname": ":radio:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "music", "podcast", "program"],
+ "moji": "📻"
+ },
+ "radio_button": {
+ "unicode": "1F518",
+ "unicode_alternates": [],
+ "name": "radio button",
+ "shortname": ":radio_button:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["input"],
+ "moji": "🔘"
+ },
+ "rage": {
+ "unicode": "1F621",
+ "unicode_alternates": [],
+ "name": "pouting face",
+ "shortname": ":rage:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["angry", "despise", "hate", "mad", "pout", "anger", "rage", "irate"],
+ "moji": "😡"
+ },
+ "railway_car": {
+ "unicode": "1F683",
+ "unicode_alternates": [],
+ "name": "railway car",
+ "shortname": ":railway_car:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "railway", "rail", "car", "coach", "train"],
+ "moji": "🚃"
+ },
+ "railway_track": {
+ "unicode": "1F6E4",
+ "unicode_alternates": [],
+ "name": "railway track",
+ "shortname": ":railway_track:",
+ "category": "travel_places",
+ "aliases": [":railroad_track:"],
+ "aliases_ascii": [],
+ "keywords": ["train", "trolley", "subway", "locomotive", "transit"]
+ },
+ "rainbow": {
+ "unicode": "1F308",
+ "unicode_alternates": [],
+ "name": "rainbow",
+ "shortname": ":rainbow:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["happy", "nature", "photo", "sky", "unicorn", "rainbow", "color", "pride", "diversity", "spectrum", "refract", "leprechaun", "gold"],
+ "moji": "🌈"
+ },
+ "raised_hand": {
+ "unicode": "270B",
+ "unicode_alternates": [],
+ "name": "raised hand",
+ "shortname": ":raised_hand:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman"],
+ "moji": "✋"
+ },
+ "raised_hands": {
+ "unicode": "1F64C",
+ "unicode_alternates": [],
+ "name": "person raising both hands in celebration",
+ "shortname": ":raised_hands:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["gesture", "hooray", "winning", "woot", "yay", "banzai"],
+ "moji": "🙌"
+ },
+ "raising_hand": {
+ "unicode": "1F64B",
+ "unicode_alternates": [],
+ "name": "happy person raising one hand",
+ "shortname": ":raising_hand:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girl", "woman", "hand", "raise", "notice", "attention", "answer"],
+ "moji": "🙋"
+ },
+ "ram": {
+ "unicode": "1F40F",
+ "unicode_alternates": [],
+ "name": "ram",
+ "shortname": ":ram:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "sheep", "ram", "sheep", "male", "horn", "horns"],
+ "moji": "🐏"
+ },
+ "ramen": {
+ "unicode": "1F35C",
+ "unicode_alternates": [],
+ "name": "steaming bowl",
+ "shortname": ":ramen:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chipsticks", "food", "japanese", "noodle", "ramen", "noodles", "bowl", "steaming", "soup"],
+ "moji": "🍜"
+ },
+ "rat": {
+ "unicode": "1F400",
+ "unicode_alternates": [],
+ "name": "rat",
+ "shortname": ":rat:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "mouse", "rat", "rodent", "crooked", "snitch"],
+ "moji": "🐀"
+ },
+ "recycle": {
+ "unicode": "267B",
+ "unicode_alternates": ["267B-FE0F"],
+ "name": "black universal recycling symbol",
+ "shortname": ":recycle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "environment", "garbage", "trash"],
+ "moji": "♻"
+ },
+ "red_car": {
+ "unicode": "1F697",
+ "unicode_alternates": [],
+ "name": "automobile",
+ "shortname": ":red_car:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle"],
+ "moji": "🚗"
+ },
+ "red_circle": {
+ "unicode": "1F534",
+ "unicode_alternates": [],
+ "name": "large red circle",
+ "shortname": ":red_circle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔴"
+ },
+ "registered": {
+ "moji": "®",
+ "unicode": "00AE",
+ "unicode_alternates": [],
+ "name": "registered sign",
+ "shortname": ":registered:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alphabet", "circle"]
+ },
+ "relaxed": {
+ "unicode": "263A",
+ "unicode_alternates": ["263A-FE0F"],
+ "name": "white smiling face",
+ "shortname": ":relaxed:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blush", "face", "happiness", "massage", "smile"],
+ "moji": "☺"
+ },
+ "relieved": {
+ "unicode": "1F60C",
+ "unicode_alternates": [],
+ "name": "relieved face",
+ "shortname": ":relieved:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "happiness", "massage", "phew", "relaxed", "relieved", "satisfied", "phew", "relief"],
+ "moji": "😌"
+ },
+ "reminder_ribbon": {
+ "unicode": "1F397",
+ "unicode_alternates": [],
+ "name": "reminder ribbon",
+ "shortname": ":reminder_ribbon:",
+ "category": "celebration",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["awareness"]
+ },
+ "repeat": {
+ "unicode": "1F501",
+ "unicode_alternates": [],
+ "name": "clockwise rightwards and leftwards open circle arr",
+ "shortname": ":repeat:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["loop", "record"],
+ "moji": "🔁"
+ },
+ "repeat_one": {
+ "unicode": "1F502",
+ "unicode_alternates": [],
+ "name": "clockwise rightwards and leftwards open circle arr",
+ "shortname": ":repeat_one:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "loop"],
+ "moji": "🔂"
+ },
+ "restroom": {
+ "unicode": "1F6BB",
+ "unicode_alternates": [],
+ "name": "restroom",
+ "shortname": ":restroom:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "woman", "man", "unisex", "bathroom", "restroom", "sign", "shared", "toilet"],
+ "moji": "🚻"
+ },
+ "revolving_hearts": {
+ "unicode": "1F49E",
+ "unicode_alternates": [],
+ "name": "revolving hearts",
+ "shortname": ":revolving_hearts:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "heart", "hearts", "revolving", "moving", "circle", "multiple", "lovers"],
+ "moji": "💞"
+ },
+ "rewind": {
+ "unicode": "23EA",
+ "unicode_alternates": [],
+ "name": "black left-pointing double triangle",
+ "shortname": ":rewind:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "play"],
+ "moji": "⏪"
+ },
+ "ribbon": {
+ "unicode": "1F380",
+ "unicode_alternates": [],
+ "name": "ribbon",
+ "shortname": ":ribbon:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bowtie", "decoration", "girl", "pink", "ribbon", "lace", "wrap", "decorate"],
+ "moji": "🎀"
+ },
+ "rice": {
+ "unicode": "1F35A",
+ "unicode_alternates": [],
+ "name": "cooked rice",
+ "shortname": ":rice:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "rice", "white", "grain", "food", "bowl"],
+ "moji": "🍚"
+ },
+ "rice_ball": {
+ "unicode": "1F359",
+ "unicode_alternates": [],
+ "name": "rice ball",
+ "shortname": ":rice_ball:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "japanese", "rice", "ball", "white", "nori", "seaweed", "japanese"],
+ "moji": "🍙"
+ },
+ "rice_cracker": {
+ "unicode": "1F358",
+ "unicode_alternates": [],
+ "name": "rice cracker",
+ "shortname": ":rice_cracker:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "japanese", "rice", "cracker", "seaweed", "food", "japanese"],
+ "moji": "🍘"
+ },
+ "rice_scene": {
+ "unicode": "1F391",
+ "unicode_alternates": [],
+ "name": "moon viewing ceremony",
+ "shortname": ":rice_scene:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "moon", "viewing", "observing", "otsukimi", "tsukimi", "rice", "scene", "festival", "autumn"],
+ "moji": "🎑"
+ },
+ "right_speaker": {
+ "unicode": "1F568",
+ "unicode_alternates": [],
+ "name": "right speaker",
+ "shortname": ":right_speaker:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "listen", "hear", "noise", "volume"]
+ },
+ "right_speaker_one": {
+ "unicode": "1F569",
+ "unicode_alternates": [],
+ "name": "right speaker with one sound wave",
+ "shortname": ":right_speaker_one:",
+ "category": "objects_symbols",
+ "aliases": [":right_speaker_with_one_sound_wave:"],
+ "aliases_ascii": [],
+ "keywords": ["low", "volume"]
+ },
+ "right_speaker_three": {
+ "unicode": "1F56A",
+ "unicode_alternates": [],
+ "name": "right speaker with three sound waves",
+ "shortname": ":right_speaker_three:",
+ "category": "objects_symbols",
+ "aliases": [":right_speaker_with_three_sound_waves:"],
+ "aliases_ascii": [],
+ "keywords": ["loud", "high", "volume"]
+ },
+ "ring": {
+ "unicode": "1F48D",
+ "unicode_alternates": [],
+ "name": "ring",
+ "shortname": ":ring:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["marriage", "propose", "valentines", "wedding"],
+ "moji": "💍"
+ },
+ "ringing_bell": {
+ "unicode": "1F56D",
+ "unicode_alternates": [],
+ "name": "ringing bell",
+ "shortname": ":ringing_bell:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alert", "ding", "volume", "sound", "chime"]
+ },
+ "rocket": {
+ "unicode": "1F680",
+ "unicode_alternates": [],
+ "name": "rocket",
+ "shortname": ":rocket:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["launch", "ship", "staffmode", "rocket", "space", "spacecraft", "astronaut", "cosmonaut"],
+ "moji": "🚀"
+ },
+ "roller_coaster": {
+ "unicode": "1F3A2",
+ "unicode_alternates": [],
+ "name": "roller coaster",
+ "shortname": ":roller_coaster:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["carnival", "fun", "photo", "play", "playground", "roller", "coaster", "amusement", "park", "fair", "ride", "entertainment"],
+ "moji": "🎢"
+ },
+ "rooster": {
+ "unicode": "1F413",
+ "unicode_alternates": [],
+ "name": "rooster",
+ "shortname": ":rooster:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "chicken", "nature", "rooster", "cockerel", "cock", "male", "cock-a-doodle-doo", "crowing"],
+ "moji": "🐓"
+ },
+ "rose": {
+ "unicode": "1F339",
+ "unicode_alternates": [],
+ "name": "rose",
+ "shortname": ":rose:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flowers", "love", "valentines", "rose", "fragrant", "flower", "thorns", "love", "petals", "romance"],
+ "moji": "🌹"
+ },
+ "rosette": {
+ "unicode": "1F3F5",
+ "unicode_alternates": [],
+ "name": "rosette",
+ "shortname": ":rosette:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flower"]
+ },
+ "rosette_black": {
+ "unicode": "1F3F6",
+ "unicode_alternates": [],
+ "name": "black rosette",
+ "shortname": ":rosette_black:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flower"]
+ },
+ "rotating_light": {
+ "unicode": "1F6A8",
+ "unicode_alternates": [],
+ "name": "police cars revolving light",
+ "shortname": ":rotating_light:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["911", "ambulance", "emergency", "police", "light", "police", "emergency"],
+ "moji": "🚨"
+ },
+ "round_pushpin": {
+ "unicode": "1F4CD",
+ "unicode_alternates": [],
+ "name": "round pushpin",
+ "shortname": ":round_pushpin:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["stationery"],
+ "moji": "📍"
+ },
+ "rowboat": {
+ "unicode": "1F6A3",
+ "unicode_alternates": [],
+ "name": "rowboat",
+ "shortname": ":rowboat:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hobby", "ship", "sports", "water", "boat", "row", "oar", "paddle"],
+ "moji": "🚣"
+ },
+ "rugby_football": {
+ "unicode": "1F3C9",
+ "unicode_alternates": [],
+ "name": "rugby football",
+ "shortname": ":rugby_football:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sports", "rugby", "football", "ball", "sport", "team", "england"],
+ "moji": "🏉"
+ },
+ "runner": {
+ "unicode": "1F3C3",
+ "unicode_alternates": [],
+ "name": "runner",
+ "shortname": ":runner:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["exercise", "man", "walking", "run", "runner", "jog", "exercise", "sprint", "race", "dash"],
+ "moji": "🏃"
+ },
+ "running_shirt_with_sash": {
+ "unicode": "1F3BD",
+ "unicode_alternates": [],
+ "name": "running shirt with sash",
+ "shortname": ":running_shirt_with_sash:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["pageant", "play", "running", "run", "shirt", "cloths", "compete", "sports"],
+ "moji": "🎽"
+ },
+ "sagittarius": {
+ "unicode": "2650",
+ "unicode_alternates": ["2650-FE0F"],
+ "name": "sagittarius",
+ "shortname": ":sagittarius:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sagittarius", "centaur", "archer", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "sign", "zodiac", "horoscope"],
+ "moji": "♐"
+ },
+ "sailboat": {
+ "unicode": "26F5",
+ "unicode_alternates": ["26F5-FE0F"],
+ "name": "sailboat",
+ "shortname": ":sailboat:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ship", "transportation"],
+ "moji": "⛵"
+ },
+ "sake": {
+ "unicode": "1F376",
+ "unicode_alternates": [],
+ "name": "sake bottle and cup",
+ "shortname": ":sake:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beverage", "drink", "drunk", "wine", "sake", "wine", "rice", "ferment", "alcohol", "japanese", "drink"],
+ "moji": "🍶"
+ },
+ "sandal": {
+ "unicode": "1F461",
+ "unicode_alternates": [],
+ "name": "womans sandal",
+ "shortname": ":sandal:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "shoes"],
+ "moji": "👡"
+ },
+ "santa": {
+ "unicode": "1F385",
+ "unicode_alternates": [],
+ "name": "father christmas",
+ "shortname": ":santa:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["christmas", "father christmas", "festival", "male", "man", "xmas", "santa", "saint nick", "jolly", "ho ho ho", "north pole", "presents", "gifts", "naughty", "nice", "sleigh", "father", "christmas", "holiday"],
+ "moji": "🎅"
+ },
+ "satellite": {
+ "unicode": "1F4E1",
+ "unicode_alternates": [],
+ "name": "satellite antenna",
+ "shortname": ":satellite:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication"],
+ "moji": "📡"
+ },
+ "satellite_orbital": {
+ "unicode": "1F6F0",
+ "unicode_alternates": [],
+ "name": "satellite",
+ "shortname": ":satellite_orbital:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "orbital", "space"]
+ },
+ "saxophone": {
+ "unicode": "1F3B7",
+ "unicode_alternates": [],
+ "name": "saxophone",
+ "shortname": ":saxophone:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["instrument", "music", "saxophone", "sax", "music", "instrument", "woodwind"],
+ "moji": "🎷"
+ },
+ "school": {
+ "unicode": "1F3EB",
+ "unicode_alternates": [],
+ "name": "school",
+ "shortname": ":school:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["building", "school", "university", "elementary", "middle", "high", "college", "teach", "education"],
+ "moji": "🏫"
+ },
+ "school_satchel": {
+ "unicode": "1F392",
+ "unicode_alternates": [],
+ "name": "school satchel",
+ "shortname": ":school_satchel:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bag", "education", "student", "school", "satchel", "backpack", "bag", "packing", "pack", "hike", "education", "adventure", "travel", "sightsee"],
+ "moji": "🎒"
+ },
+ "scissors": {
+ "unicode": "2702",
+ "unicode_alternates": ["2702-FE0F"],
+ "name": "black scissors",
+ "shortname": ":scissors:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cut", "stationery"],
+ "moji": "✂"
+ },
+ "scorpius": {
+ "unicode": "264F",
+ "unicode_alternates": ["264F-FE0F"],
+ "name": "scorpius",
+ "shortname": ":scorpius:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["scorpius", "scorpion", "scorpio", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "sign", "zodiac", "horoscope"],
+ "moji": "♏"
+ },
+ "scream": {
+ "unicode": "1F631",
+ "unicode_alternates": [],
+ "name": "face screaming in fear",
+ "shortname": ":scream:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "munch", "scream", "painting", "artist", "alien"],
+ "moji": "😱"
+ },
+ "scream_cat": {
+ "unicode": "1F640",
+ "unicode_alternates": [],
+ "name": "weary cat face",
+ "shortname": ":scream_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "munch", "weary", "sleepy", "tired", "tiredness", "study", "finals", "school", "exhausted", "scream", "painting", "artist"],
+ "moji": "🙀"
+ },
+ "scroll": {
+ "unicode": "1F4DC",
+ "unicode_alternates": [],
+ "name": "scroll",
+ "shortname": ":scroll:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["documents"],
+ "moji": "📜"
+ },
+ "seat": {
+ "unicode": "1F4BA",
+ "unicode_alternates": [],
+ "name": "seat",
+ "shortname": ":seat:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sit"],
+ "moji": "💺"
+ },
+ "secret": {
+ "unicode": "3299",
+ "unicode_alternates": ["3299-FE0F"],
+ "name": "circled ideograph secret",
+ "shortname": ":secret:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["privacy"],
+ "moji": "㊙"
+ },
+ "see_no_evil": {
+ "unicode": "1F648",
+ "unicode_alternates": [],
+ "name": "see-no-evil monkey",
+ "shortname": ":see_no_evil:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "monkey", "nature", "monkey", "see", "eyes", "vision", "sight", "mizaru"],
+ "moji": "🙈"
+ },
+ "seedling": {
+ "unicode": "1F331",
+ "unicode_alternates": [],
+ "name": "seedling",
+ "shortname": ":seedling:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["grass", "lawn", "nature", "plant", "seedling", "plant", "new", "start", "grow"],
+ "moji": "🌱"
+ },
+ "seven": {
+ "moji": "7️⃣",
+ "unicode": "0037-20E3",
+ "unicode_alternates": ["0037-FE0F-20E3"],
+ "name": "digit seven",
+ "shortname": ":seven:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["7", "blue-square", "numbers", "prime"]
+ },
+ "shaved_ice": {
+ "unicode": "1F367",
+ "unicode_alternates": [],
+ "name": "shaved ice",
+ "shortname": ":shaved_ice:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["desert", "hot", "shaved", "ice", "dessert", "treat", "syrup", "flavoring"],
+ "moji": "🍧"
+ },
+ "sheep": {
+ "unicode": "1F411",
+ "unicode_alternates": [],
+ "name": "sheep",
+ "shortname": ":sheep:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "sheep", "wool", "flock", "follower", "ewe", "female", "lamb"],
+ "moji": "🐑"
+ },
+ "shell": {
+ "unicode": "1F41A",
+ "unicode_alternates": [],
+ "name": "spiral shell",
+ "shortname": ":shell:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beach", "nature", "sea", "shell", "spiral", "beach", "sand", "crab", "nautilus"],
+ "moji": "🐚"
+ },
+ "shield": {
+ "unicode": "1F6E1",
+ "unicode_alternates": [],
+ "name": "shield",
+ "shortname": ":shield:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["interstate", "route", "sign", "highway", "interstate"]
+ },
+ "ship": {
+ "unicode": "1F6A2",
+ "unicode_alternates": [],
+ "name": "ship",
+ "shortname": ":ship:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["titanic", "transportation", "ferry", "ship", "boat"],
+ "moji": "🚢"
+ },
+ "shirt": {
+ "unicode": "1F455",
+ "unicode_alternates": [],
+ "name": "t-shirt",
+ "shortname": ":shirt:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cloth", "fashion"],
+ "moji": "👕"
+ },
+ "shopping_bags": {
+ "unicode": "1F6CD",
+ "unicode_alternates": [],
+ "name": "shopping bags",
+ "shortname": ":shopping_bags:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["purchase", "mall", "buy", "store", "shop"]
+ },
+ "shower": {
+ "unicode": "1F6BF",
+ "unicode_alternates": [],
+ "name": "shower",
+ "shortname": ":shower:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bath", "clean", "wash", "bathroom", "shower", "soap", "water", "clean", "shampoo", "lather"],
+ "moji": "🚿"
+ },
+ "signal_strength": {
+ "unicode": "1F4F6",
+ "unicode_alternates": [],
+ "name": "antenna with bars",
+ "shortname": ":signal_strength:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "📶"
+ },
+ "six": {
+ "moji": "6️⃣",
+ "unicode": "0036-20E3",
+ "unicode_alternates": ["0036-FE0F-20E3"],
+ "name": "digit six",
+ "shortname": ":six:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["6", "blue-square", "numbers"]
+ },
+ "six_pointed_star": {
+ "unicode": "1F52F",
+ "unicode_alternates": [],
+ "name": "six pointed star with middle dot",
+ "shortname": ":six_pointed_star:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["purple-square"],
+ "moji": "🔯"
+ },
+ "ski": {
+ "unicode": "1F3BF",
+ "unicode_alternates": [],
+ "name": "ski and ski boot",
+ "shortname": ":ski:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cold", "sports", "winter", "ski", "downhill", "cross-country", "poles", "snow", "winter", "mountain", "alpine", "powder", "slalom", "freestyle"],
+ "moji": "🎿"
+ },
+ "skull": {
+ "unicode": "1F480",
+ "unicode_alternates": [],
+ "name": "skull",
+ "shortname": ":skull:",
+ "category": "emoticons",
+ "aliases": [":skeleton:"],
+ "aliases_ascii": [],
+ "keywords": ["dead", "skeleton", "dying"],
+ "moji": "💀"
+ },
+ "sleeping": {
+ "unicode": "1F634",
+ "unicode_alternates": [],
+ "name": "sleeping face",
+ "shortname": ":sleeping:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "sleepy", "tired", "sleep", "sleepy", "sleeping", "snore"],
+ "moji": "😴"
+ },
+ "sleeping_accommodation": {
+ "unicode": "1F6CC",
+ "unicode_alternates": [],
+ "name": "sleeping accommodation",
+ "shortname": ":sleeping_accommodation:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["hotel", "motel", "rest"]
+ },
+ "sleepy": {
+ "unicode": "1F62A",
+ "unicode_alternates": [],
+ "name": "sleepy face",
+ "shortname": ":sleepy:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "rest", "tired", "sleepy", "tired", "exhausted"],
+ "moji": "😪"
+ },
+ "slight_frown": {
+ "unicode": "1F641",
+ "unicode_alternates": [],
+ "name": "slightly frowning face",
+ "shortname": ":slight_frown:",
+ "category": "people",
+ "aliases": [":slightly_frowning_face:"],
+ "aliases_ascii": [],
+ "keywords": ["slight", "frown", "unhappy", "disappointed"]
+ },
+ "slight_smile": {
+ "unicode": "1F642",
+ "unicode_alternates": [],
+ "name": "slightly smiling face",
+ "shortname": ":slight_smile:",
+ "category": "people",
+ "aliases": [":slightly_smiling_face:"],
+ "aliases_ascii": [],
+ "keywords": ["slight", "smile", "happy"]
+ },
+ "slot_machine": {
+ "unicode": "1F3B0",
+ "unicode_alternates": [],
+ "name": "slot machine",
+ "shortname": ":slot_machine:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bet", "gamble", "vegas", "slot", "machine", "gamble", "one-armed bandit", "slots", "luck"],
+ "moji": "🎰"
+ },
+ "small_blue_diamond": {
+ "unicode": "1F539",
+ "unicode_alternates": [],
+ "name": "small blue diamond",
+ "shortname": ":small_blue_diamond:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔹"
+ },
+ "small_orange_diamond": {
+ "unicode": "1F538",
+ "unicode_alternates": [],
+ "name": "small orange diamond",
+ "shortname": ":small_orange_diamond:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔸"
+ },
+ "small_red_triangle": {
+ "unicode": "1F53A",
+ "unicode_alternates": [],
+ "name": "up-pointing red triangle",
+ "shortname": ":small_red_triangle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔺"
+ },
+ "small_red_triangle_down": {
+ "unicode": "1F53B",
+ "unicode_alternates": [],
+ "name": "down-pointing red triangle",
+ "shortname": ":small_red_triangle_down:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔻"
+ },
+ "smile": {
+ "unicode": "1F604",
+ "unicode_alternates": [],
+ "name": "smiling face with open mouth and smiling eyes",
+ "shortname": ":smile:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":)", ":-)", "=]", "=)", ":]"],
+ "keywords": ["face", "funny", "haha", "happy", "joy", "laugh", "smile", "smiley", "smiling"],
+ "moji": "😄"
+ },
+ "smile_cat": {
+ "unicode": "1F638",
+ "unicode_alternates": [],
+ "name": "grinning cat face with smiling eyes",
+ "shortname": ":smile_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "cat", "smile", "grin", "grinning"],
+ "moji": "😸"
+ },
+ "smiley": {
+ "unicode": "1F603",
+ "unicode_alternates": [],
+ "name": "smiling face with open mouth",
+ "shortname": ":smiley:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":D", ":-D", "=D"],
+ "keywords": ["face", "haha", "happy", "joy", "smiling", "smile", "smiley"],
+ "moji": "😃"
+ },
+ "smiley_cat": {
+ "unicode": "1F63A",
+ "unicode_alternates": [],
+ "name": "smiling cat face with open mouth",
+ "shortname": ":smiley_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "happy", "smile", "smiley", "cat", "happy"],
+ "moji": "😺"
+ },
+ "smiling_imp": {
+ "unicode": "1F608",
+ "unicode_alternates": [],
+ "name": "smiling face with horns",
+ "shortname": ":smiling_imp:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["devil", "horns", "horns", "devil", "impish", "trouble"],
+ "moji": "😈"
+ },
+ "smirk": {
+ "unicode": "1F60F",
+ "unicode_alternates": [],
+ "name": "smirking face",
+ "shortname": ":smirk:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mean", "prank", "smile", "smug", "smirking", "smirk", "smug", "smile", "half-smile", "conceited"],
+ "moji": "😏"
+ },
+ "smirk_cat": {
+ "unicode": "1F63C",
+ "unicode_alternates": [],
+ "name": "cat face with wry smile",
+ "shortname": ":smirk_cat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cats", "smirk", "smirking", "wry", "confident", "confidence"],
+ "moji": "😼"
+ },
+ "smoking": {
+ "unicode": "1F6AC",
+ "unicode_alternates": [],
+ "name": "smoking symbol",
+ "shortname": ":smoking:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cigarette", "kills", "tobacco", "smoking", "cigarette", "smoke", "cancer", "lungs", "inhale", "tar", "nicotine"],
+ "moji": "🚬"
+ },
+ "snail": {
+ "unicode": "1F40C",
+ "unicode_alternates": [],
+ "name": "snail",
+ "shortname": ":snail:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "shell", "slow", "snail", "slow", "escargot", "french", "appetizer"],
+ "moji": "🐌"
+ },
+ "snake": {
+ "unicode": "1F40D",
+ "unicode_alternates": [],
+ "name": "snake",
+ "shortname": ":snake:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "evil"],
+ "moji": "🐍"
+ },
+ "snowboarder": {
+ "unicode": "1F3C2",
+ "unicode_alternates": [],
+ "name": "snowboarder",
+ "shortname": ":snowboarder:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sports", "winter", "snow", "boarding", "sports", "freestyle", "halfpipe", "board", "mountain", "alpine", "winter"],
+ "moji": "🏂"
+ },
+ "snowflake": {
+ "unicode": "2744",
+ "unicode_alternates": ["2744-FE0F"],
+ "name": "snowflake",
+ "shortname": ":snowflake:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["christmas", "cold", "season", "weather", "winter", "xmas", "snowflake", "snow", "frozen", "droplet", "ice", "crystal", "cold", "chilly", "winter", "unique", "special", "below zero", "elsa"],
+ "moji": "❄"
+ },
+ "snowman": {
+ "unicode": "26C4",
+ "unicode_alternates": ["26C4-FE0F"],
+ "name": "snowman without snow",
+ "shortname": ":snowman:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["christmas", "cold", "season", "weather", "winter", "xmas"],
+ "moji": "⛄"
+ },
+ "sob": {
+ "unicode": "1F62D",
+ "unicode_alternates": [],
+ "name": "loudly crying face",
+ "shortname": ":sob:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cry", "face", "sad", "tears", "upset", "cry", "sob", "tears", "sad", "melancholy", "morn", "somber", "hurt"],
+ "moji": "😭"
+ },
+ "soccer": {
+ "unicode": "26BD",
+ "unicode_alternates": ["26BD-FE0F"],
+ "name": "soccer ball",
+ "shortname": ":soccer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["balls", "fifa", "football", "sports", "european", "football"],
+ "moji": "⚽"
+ },
+ "soon": {
+ "unicode": "1F51C",
+ "unicode_alternates": [],
+ "name": "soon with rightwards arrow above",
+ "shortname": ":soon:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arrow", "words"],
+ "moji": "🔜"
+ },
+ "sos": {
+ "unicode": "1F198",
+ "unicode_alternates": [],
+ "name": "squared sos",
+ "shortname": ":sos:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["emergency", "help", "red-square", "words"],
+ "moji": "🆘"
+ },
+ "sound": {
+ "unicode": "1F509",
+ "unicode_alternates": [],
+ "name": "speaker with one sound wave",
+ "shortname": ":sound:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["speaker", "volume"],
+ "moji": "🔉"
+ },
+ "space_invader": {
+ "unicode": "1F47E",
+ "unicode_alternates": [],
+ "name": "alien monster",
+ "shortname": ":space_invader:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arcade", "game"],
+ "moji": "👾"
+ },
+ "spades": {
+ "unicode": "2660",
+ "unicode_alternates": ["2660-FE0F"],
+ "name": "black spade suit",
+ "shortname": ":spades:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cards", "poker"],
+ "moji": "♠"
+ },
+ "spaghetti": {
+ "unicode": "1F35D",
+ "unicode_alternates": [],
+ "name": "spaghetti",
+ "shortname": ":spaghetti:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "italian", "noodle", "spaghetti", "noodles", "tomato", "sauce", "italian"],
+ "moji": "🍝"
+ },
+ "sparkle": {
+ "unicode": "2747",
+ "unicode_alternates": ["2747-FE0F"],
+ "name": "sparkle",
+ "shortname": ":sparkle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["green-square", "stars"],
+ "moji": "❇"
+ },
+ "sparkler": {
+ "unicode": "1F387",
+ "unicode_alternates": [],
+ "name": "firework sparkler",
+ "shortname": ":sparkler:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "shine", "stars"],
+ "moji": "🎇"
+ },
+ "sparkles": {
+ "unicode": "2728",
+ "unicode_alternates": [],
+ "name": "sparkles",
+ "shortname": ":sparkles:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cool", "shine", "shiny", "stars"],
+ "moji": "✨"
+ },
+ "sparkling_heart": {
+ "unicode": "1F496",
+ "unicode_alternates": [],
+ "name": "sparkling heart",
+ "shortname": ":sparkling_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines"],
+ "moji": "💖"
+ },
+ "speak_no_evil": {
+ "unicode": "1F64A",
+ "unicode_alternates": [],
+ "name": "speak-no-evil monkey",
+ "shortname": ":speak_no_evil:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "monkey", "monkey", "mouth", "talk", "say", "words", "verbal", "verbalize", "oral", "iwazaru"],
+ "moji": "🙊"
+ },
+ "speaker": {
+ "unicode": "1F508",
+ "unicode_alternates": [],
+ "name": "speaker",
+ "shortname": ":speaker:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sound", "listen", "hear", "noise"]
+ },
+ "speaking_head": {
+ "unicode": "1F5E3",
+ "unicode_alternates": [],
+ "name": "speaking head in silhouette",
+ "shortname": ":speaking_head:",
+ "category": "objects_symbols",
+ "aliases": [":speaking_head_in_silhouette:"],
+ "aliases_ascii": [],
+ "keywords": ["talk"]
+ },
+ "speech_balloon": {
+ "unicode": "1F4AC",
+ "unicode_alternates": [],
+ "name": "speech balloon",
+ "shortname": ":speech_balloon:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bubble", "words", "speech", "balloon", "talk", "conversation", "communication", "comic", "dialogue"],
+ "moji": "💬"
+ },
+ "speech_left": {
+ "unicode": "1F5E8",
+ "unicode_alternates": [],
+ "name": "left speech bubble",
+ "shortname": ":speech_left:",
+ "category": "objects_symbols",
+ "aliases": [":left_speech_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "words", "talk", "conversation", "communication", "comic", "dialogue"]
+ },
+ "speech_right": {
+ "unicode": "1F5E9",
+ "unicode_alternates": [],
+ "name": "right speech bubble",
+ "shortname": ":speech_right:",
+ "category": "objects_symbols",
+ "aliases": [":right_speech_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "words", "talk", "conversation", "communication", "comic", "dialogue"]
+ },
+ "speech_three": {
+ "unicode": "1F5EB",
+ "unicode_alternates": [],
+ "name": "three speech bubbles",
+ "shortname": ":speech_three:",
+ "category": "objects_symbols",
+ "aliases": [":three_speech_bubbles:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "words", "talk", "conversation", "communication", "comic", "dialogue"]
+ },
+ "speech_two": {
+ "unicode": "1F5EA",
+ "unicode_alternates": [],
+ "name": "two speech bubbles",
+ "shortname": ":speech_two:",
+ "category": "objects_symbols",
+ "aliases": [":two_speech_bubbles:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "words", "talk", "conversation", "communication", "comic", "dialogue"]
+ },
+ "speedboat": {
+ "unicode": "1F6A4",
+ "unicode_alternates": [],
+ "name": "speedboat",
+ "shortname": ":speedboat:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ship", "transportation", "vehicle", "motor", "speed", "ski", "power", "boat"],
+ "moji": "🚤"
+ },
+ "spider": {
+ "unicode": "1F577",
+ "unicode_alternates": [],
+ "name": "spider",
+ "shortname": ":spider:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["arachnid", "eight-legged"]
+ },
+ "spider_web": {
+ "unicode": "1F578",
+ "unicode_alternates": [],
+ "name": "spider web",
+ "shortname": ":spider_web:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cobweb"]
+ },
+ "spy": {
+ "unicode": "1F575",
+ "unicode_alternates": [],
+ "name": "sleuth or spy",
+ "shortname": ":spy:",
+ "category": "people",
+ "aliases": [":sleuth_or_spy:"],
+ "aliases_ascii": [],
+ "keywords": ["pi", "undercover", "investigator"]
+ },
+ "stadium": {
+ "unicode": "1F3DF",
+ "unicode_alternates": [],
+ "name": "stadium",
+ "shortname": ":stadium:",
+ "category": "travel_places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sport", "event", "concert", "convention", "game"]
+ },
+ "star": {
+ "unicode": "2B50",
+ "unicode_alternates": ["2B50-FE0F"],
+ "name": "white medium star",
+ "shortname": ":star:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "yellow"],
+ "moji": "⭐"
+ },
+ "star2": {
+ "unicode": "1F31F",
+ "unicode_alternates": [],
+ "name": "glowing star",
+ "shortname": ":star2:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "sparkle", "glow", "glowing", "star", "five", "points", "classic"],
+ "moji": "🌟"
+ },
+ "stars": {
+ "unicode": "1F320",
+ "unicode_alternates": [],
+ "name": "shooting star",
+ "shortname": ":stars:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["night", "photo", "shooting", "shoot", "star", "sky", "night", "comet", "meteoroid"],
+ "moji": "🌠"
+ },
+ "station": {
+ "unicode": "1F689",
+ "unicode_alternates": [],
+ "name": "station",
+ "shortname": ":station:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["public", "transportation", "vehicle", "station", "train", "subway"],
+ "moji": "🚉"
+ },
+ "statue_of_liberty": {
+ "unicode": "1F5FD",
+ "unicode_alternates": [],
+ "name": "statue of liberty",
+ "shortname": ":statue_of_liberty:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["american", "newyork"],
+ "moji": "🗽"
+ },
+ "steam_locomotive": {
+ "unicode": "1F682",
+ "unicode_alternates": [],
+ "name": "steam locomotive",
+ "shortname": ":steam_locomotive:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["train", "transportation", "vehicle", "locomotive", "steam", "train", "engine"],
+ "moji": "🚂"
+ },
+ "stereo": {
+ "unicode": "1F4FE",
+ "unicode_alternates": [],
+ "name": "portable stereo",
+ "shortname": ":stereo:",
+ "category": "objects_symbols",
+ "aliases": [":portable_stereo:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "music", "program", "boom", "box"]
+ },
+ "stew": {
+ "unicode": "1F372",
+ "unicode_alternates": [],
+ "name": "pot of food",
+ "shortname": ":stew:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "meat", "stew", "hearty", "soup", "thick", "hot", "pot"],
+ "moji": "🍲"
+ },
+ "stock_chart": {
+ "unicode": "1F5E0",
+ "unicode_alternates": [],
+ "name": "stock chart",
+ "shortname": ":stock_chart:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["graph", "presentation", "stats", "business"]
+ },
+ "straight_ruler": {
+ "unicode": "1F4CF",
+ "unicode_alternates": [],
+ "name": "straight ruler",
+ "shortname": ":straight_ruler:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["stationery"],
+ "moji": "📏"
+ },
+ "strawberry": {
+ "unicode": "1F353",
+ "unicode_alternates": [],
+ "name": "strawberry",
+ "shortname": ":strawberry:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "strawberry", "short", "cake", "berry"],
+ "moji": "🍓"
+ },
+ "stuck_out_tongue": {
+ "unicode": "1F61B",
+ "unicode_alternates": [],
+ "name": "face with stuck-out tongue",
+ "shortname": ":stuck_out_tongue:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [":P", ":-P", "=P", ":-p", ":p", "=p", ":-Þ", ":Þ", ":þ", ":-þ", ":-b", ":b", "d:"],
+ "keywords": ["childish", "face", "mischievous", "playful", "prank", "tongue", "silly", "playful", "cheeky"],
+ "moji": "😛"
+ },
+ "stuck_out_tongue_closed_eyes": {
+ "unicode": "1F61D",
+ "unicode_alternates": [],
+ "name": "face with stuck-out tongue and tightly-closed eyes",
+ "shortname": ":stuck_out_tongue_closed_eyes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "mischievous", "playful", "prank", "tongue", "kidding", "silly", "playful", "ecstatic"],
+ "moji": "😝"
+ },
+ "stuck_out_tongue_winking_eye": {
+ "unicode": "1F61C",
+ "unicode_alternates": [],
+ "name": "face with stuck-out tongue and winking eye",
+ "shortname": ":stuck_out_tongue_winking_eye:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [">:P", "X-P", "x-p"],
+ "keywords": ["childish", "face", "mischievous", "playful", "prank", "tongue", "wink", "winking", "kidding", "silly", "playful", "crazy"],
+ "moji": "😜"
+ },
+ "sun_with_face": {
+ "unicode": "1F31E",
+ "unicode_alternates": [],
+ "name": "sun with face",
+ "shortname": ":sun_with_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["morning", "sun", "anthropomorphic", "face", "sky"],
+ "moji": "🌞"
+ },
+ "sunflower": {
+ "unicode": "1F33B",
+ "unicode_alternates": [],
+ "name": "sunflower",
+ "shortname": ":sunflower:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "sunflower", "sun", "flower", "seeds", "yellow"],
+ "moji": "🌻"
+ },
+ "sunglasses": {
+ "unicode": "1F60E",
+ "unicode_alternates": [],
+ "name": "smiling face with sunglasses",
+ "shortname": ":sunglasses:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["B-)", "B)", "8)", "8-)", "B-D", "8-D"],
+ "keywords": ["cool", "face", "smiling", "sunglasses", "sun", "glasses", "sunny", "cool", "smooth"],
+ "moji": "😎"
+ },
+ "sunny": {
+ "unicode": "2600",
+ "unicode_alternates": ["2600-FE0F"],
+ "name": "black sun with rays",
+ "shortname": ":sunny:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["brightness", "weather"]
+ },
+ "sunrise": {
+ "unicode": "1F305",
+ "unicode_alternates": [],
+ "name": "sunrise",
+ "shortname": ":sunrise:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["morning", "photo", "vacation", "view", "sunrise", "sun", "morning", "color", "sky"],
+ "moji": "🌅"
+ },
+ "sunrise_over_mountains": {
+ "unicode": "1F304",
+ "unicode_alternates": [],
+ "name": "sunrise over mountains",
+ "shortname": ":sunrise_over_mountains:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["photo", "vacation", "view", "sunrise", "sun", "morning", "mountain", "rural", "color", "sky"],
+ "moji": "🌄"
+ },
+ "surfer": {
+ "unicode": "1F3C4",
+ "unicode_alternates": [],
+ "name": "surfer",
+ "shortname": ":surfer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ocean", "sea", "sports", "surfer", "surf", "wave", "ocean", "ride", "swell"],
+ "moji": "🏄"
+ },
+ "sushi": {
+ "unicode": "1F363",
+ "unicode_alternates": [],
+ "name": "sushi",
+ "shortname": ":sushi:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "japanese", "sushi", "fish", "raw", "nigiri", "japanese"],
+ "moji": "🍣"
+ },
+ "suspension_railway": {
+ "unicode": "1F69F",
+ "unicode_alternates": [],
+ "name": "suspension railway",
+ "shortname": ":suspension_railway:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "suspension", "railway", "rail", "train", "transportation"],
+ "moji": "🚟"
+ },
+ "sweat": {
+ "unicode": "1F613",
+ "unicode_alternates": [],
+ "name": "face with cold sweat",
+ "shortname": ":sweat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["':(", "':-(", "'=("],
+ "keywords": ["cold", "sweat", "sick", "anxious", "worried", "clammy", "diaphoresis", "face", "hot"],
+ "moji": "😓"
+ },
+ "sweat_drops": {
+ "unicode": "1F4A6",
+ "unicode_alternates": [],
+ "name": "splashing sweat symbol",
+ "shortname": ":sweat_drops:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["water"],
+ "moji": "💦"
+ },
+ "sweat_smile": {
+ "unicode": "1F605",
+ "unicode_alternates": [],
+ "name": "smiling face with open mouth and cold sweat",
+ "shortname": ":sweat_smile:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": ["':)", "':-)", "'=)", "':D", "':-D", "'=D"],
+ "keywords": ["face", "happy", "hot", "smiling", "cold", "sweat", "perspiration"],
+ "moji": "😅"
+ },
+ "sweet_potato": {
+ "unicode": "1F360",
+ "unicode_alternates": [],
+ "name": "roasted sweet potato",
+ "shortname": ":sweet_potato:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "nature", "sweet", "potato", "potassium", "roasted", "roast"],
+ "moji": "🍠"
+ },
+ "swimmer": {
+ "unicode": "1F3CA",
+ "unicode_alternates": [],
+ "name": "swimmer",
+ "shortname": ":swimmer:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sports", "swimmer", "swim", "water", "pool", "laps", "freestyle", "butterfly", "breaststroke", "backstroke"],
+ "moji": "🏊"
+ },
+ "symbols": {
+ "unicode": "1F523",
+ "unicode_alternates": [],
+ "name": "input symbol for symbols",
+ "shortname": ":symbols:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "🔣"
+ },
+ "syringe": {
+ "unicode": "1F489",
+ "unicode_alternates": [],
+ "name": "syringe",
+ "shortname": ":syringe:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blood", "drugs", "health", "hospital", "medicine", "needle"],
+ "moji": "💉"
+ },
+ "tada": {
+ "unicode": "1F389",
+ "unicode_alternates": [],
+ "name": "party popper",
+ "shortname": ":tada:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["contulations", "party", "party", "popper", "tada", "celebration", "victory", "announcement", "climax", "congratulations"],
+ "moji": "🎉"
+ },
+ "tanabata_tree": {
+ "unicode": "1F38B",
+ "unicode_alternates": [],
+ "name": "tanabata tree",
+ "shortname": ":tanabata_tree:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "plant", "tanabata", "tree", "festival", "star", "wish", "holiday"],
+ "moji": "🎋"
+ },
+ "tangerine": {
+ "unicode": "1F34A",
+ "unicode_alternates": [],
+ "name": "tangerine",
+ "shortname": ":tangerine:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "tangerine", "citrus", "orange"],
+ "moji": "🍊"
+ },
+ "taurus": {
+ "unicode": "2649",
+ "unicode_alternates": ["2649-FE0F"],
+ "name": "taurus",
+ "shortname": ":taurus:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["purple-square", "sign", "taurus", "bull", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "zodiac", "horoscope"],
+ "moji": "♉"
+ },
+ "taxi": {
+ "unicode": "1F695",
+ "unicode_alternates": [],
+ "name": "taxi",
+ "shortname": ":taxi:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "transportation", "uber", "vehicle", "taxi", "car", "automobile", "city", "transport", "service"],
+ "moji": "🚕"
+ },
+ "tea": {
+ "unicode": "1F375",
+ "unicode_alternates": [],
+ "name": "teacup without handle",
+ "shortname": ":tea:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bowl", "breakfast", "british", "drink", "green", "tea", "leaf", "drink", "teacup", "hot", "beverage"],
+ "moji": "🍵"
+ },
+ "telephone": {
+ "unicode": "260E",
+ "unicode_alternates": ["260E-FE0F"],
+ "name": "black telephone",
+ "shortname": ":telephone:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "dial", "technology"],
+ "moji": "☎"
+ },
+ "telephone_black": {
+ "unicode": "1F57F",
+ "unicode_alternates": [],
+ "name": "black touchtone telephone",
+ "shortname": ":telephone_black:",
+ "category": "objects_symbols",
+ "aliases": [":black_touchtone_telephone:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "dial", "technology"]
+ },
+ "telephone_receiver": {
+ "unicode": "1F4DE",
+ "unicode_alternates": [],
+ "name": "telephone receiver",
+ "shortname": ":telephone_receiver:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["communication", "dial", "technology"],
+ "moji": "📞"
+ },
+ "telephone_white": {
+ "unicode": "1F57E",
+ "unicode_alternates": [],
+ "name": "white touchtone telephone",
+ "shortname": ":telephone_white:",
+ "category": "objects_symbols",
+ "aliases": [":white_touchtone_telephone:"],
+ "aliases_ascii": [],
+ "keywords": ["communication", "dial", "technology"]
+ },
+ "telescope": {
+ "unicode": "1F52D",
+ "unicode_alternates": [],
+ "name": "telescope",
+ "shortname": ":telescope:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["space", "stars"],
+ "moji": "🔭"
+ },
+ "tennis": {
+ "unicode": "1F3BE",
+ "unicode_alternates": [],
+ "name": "tennis racquet and ball",
+ "shortname": ":tennis:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["balls", "green", "sports", "tennis", "racket", "racquet", "ball", "game", "net", "court", "love"],
+ "moji": "🎾"
+ },
+ "tent": {
+ "unicode": "26FA",
+ "unicode_alternates": ["26FA-FE0F"],
+ "name": "tent",
+ "shortname": ":tent:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["camp", "outdoors", "photo"],
+ "moji": "⛺"
+ },
+ "thermometer": {
+ "unicode": "1F321",
+ "unicode_alternates": [],
+ "name": "thermometer",
+ "shortname": ":thermometer:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["temperature"]
+ },
+ "thought_balloon": {
+ "unicode": "1F4AD",
+ "unicode_alternates": [],
+ "name": "thought balloon",
+ "shortname": ":thought_balloon:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bubble", "cloud", "speech", "thought", "balloon", "comic", "think", "day dream", "wonder"],
+ "moji": "💭"
+ },
+ "thought_left": {
+ "unicode": "1F5EC",
+ "unicode_alternates": [],
+ "name": "left thought bubble",
+ "shortname": ":thought_left:",
+ "category": "objects_symbols",
+ "aliases": [":left_thought_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "cloud", "comic", "think", "day dream", "wonder"]
+ },
+ "thought_right": {
+ "unicode": "1F5ED",
+ "unicode_alternates": [],
+ "name": "right thought bubble",
+ "shortname": ":thought_right:",
+ "category": "objects_symbols",
+ "aliases": [":right_thought_bubble:"],
+ "aliases_ascii": [],
+ "keywords": ["balloon", "cloud", "comic", "think", "day dream", "wonder"]
+ },
+ "three": {
+ "moji": "3️⃣",
+ "unicode": "0033-20E3",
+ "unicode_alternates": ["0033-FE0F-20E3"],
+ "name": "digit three",
+ "shortname": ":three:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["3", "blue-square", "numbers", "prime"]
+ },
+ "thumbs_down_reverse": {
+ "unicode": "1F593",
+ "unicode_alternates": [],
+ "name": "reversed thumbs down sign",
+ "shortname": ":thumbs_down_reverse:",
+ "category": "people",
+ "aliases": [":reversed_thumbs_down_sign:"],
+ "aliases_ascii": [],
+ "keywords": ["hand", "no", "-1"]
+ },
+ "thumbs_up_reverse": {
+ "unicode": "1F592",
+ "unicode_alternates": [],
+ "name": "reversed thumbs up sign",
+ "shortname": ":thumbs_up_reverse:",
+ "category": "people",
+ "aliases": [":reversed_thumbs_up_sign:"],
+ "aliases_ascii": [],
+ "keywords": ["cool", "hand", "like", "yes", "+1"]
+ },
+ "thumbsdown": {
+ "unicode": "1F44E",
+ "unicode_alternates": [],
+ "name": "thumbs down sign",
+ "shortname": ":thumbsdown:",
+ "category": "emoticons",
+ "aliases": [":-1:"],
+ "aliases_ascii": [],
+ "keywords": ["hand", "no"],
+ "moji": "👎"
+ },
+ "thumbsup": {
+ "unicode": "1F44D",
+ "unicode_alternates": [],
+ "name": "thumbs up sign",
+ "shortname": ":thumbsup:",
+ "category": "emoticons",
+ "aliases": [":+1:"],
+ "aliases_ascii": [],
+ "keywords": ["cool", "hand", "like", "yes"],
+ "moji": "👍"
+ },
+ "ticket": {
+ "unicode": "1F3AB",
+ "unicode_alternates": [],
+ "name": "ticket",
+ "shortname": ":ticket:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["concert", "event", "pass", "ticket", "show", "entertainment", "stub", "admission", "proof", "purchase"],
+ "moji": "🎫"
+ },
+ "tickets": {
+ "unicode": "1F39F",
+ "unicode_alternates": [],
+ "name": "admission tickets",
+ "shortname": ":tickets:",
+ "category": "activity",
+ "aliases": [":admission_tickets:"],
+ "aliases_ascii": [],
+ "keywords": ["concert", "event", "pass", "show", "entertainment", "stub", "proof", "purchase"]
+ },
+ "tiger": {
+ "unicode": "1F42F",
+ "unicode_alternates": [],
+ "name": "tiger face",
+ "shortname": ":tiger:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal"],
+ "moji": "🐯"
+ },
+ "tiger2": {
+ "unicode": "1F405",
+ "unicode_alternates": [],
+ "name": "tiger",
+ "shortname": ":tiger2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "tiger", "cat", "striped", "tony", "tigger", "hobs"],
+ "moji": "🐅"
+ },
+ "tired_face": {
+ "unicode": "1F62B",
+ "unicode_alternates": [],
+ "name": "tired face",
+ "shortname": ":tired_face:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "frustrated", "sick", "upset", "whine", "exhausted", "sleepy", "tired"],
+ "moji": "😫"
+ },
+ "toilet": {
+ "unicode": "1F6BD",
+ "unicode_alternates": [],
+ "name": "toilet",
+ "shortname": ":toilet:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["restroom", "wc", "toilet", "bathroom", "throne", "porcelain", "waste", "flush", "plumbing"],
+ "moji": "🚽"
+ },
+ "tokyo_tower": {
+ "unicode": "1F5FC",
+ "unicode_alternates": [],
+ "name": "tokyo tower",
+ "shortname": ":tokyo_tower:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japan", "photo"],
+ "moji": "🗼"
+ },
+ "tomato": {
+ "unicode": "1F345",
+ "unicode_alternates": [],
+ "name": "tomato",
+ "shortname": ":tomato:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "nature", "vegetable", "tomato", "fruit", "sauce", "italian"],
+ "moji": "🍅"
+ },
+ "tongue": {
+ "unicode": "1F445",
+ "unicode_alternates": [],
+ "name": "tongue",
+ "shortname": ":tongue:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mouth", "playful", "tongue", "mouth", "taste", "buds", "food", "silly", "playful", "tease", "kiss", "french kiss", "lick", "tasty", "playfulness", "silliness", "intimacy"],
+ "moji": "👅"
+ },
+ "tools": {
+ "unicode": "1F6E0",
+ "unicode_alternates": [],
+ "name": "hammer and wrench",
+ "shortname": ":tools:",
+ "category": "objects_symbols",
+ "aliases": [":hammer_and_wrench:"],
+ "aliases_ascii": [],
+ "keywords": ["tools"]
+ },
+ "top": {
+ "unicode": "1F51D",
+ "unicode_alternates": [],
+ "name": "top with upwards arrow above",
+ "shortname": ":top:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "words"],
+ "moji": "🔝"
+ },
+ "tophat": {
+ "unicode": "1F3A9",
+ "unicode_alternates": [],
+ "name": "top hat",
+ "shortname": ":tophat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["classy", "gentleman", "magic", "top", "hat", "cap", "beaver", "high", "tall", "stove", "pipe", "chimney", "topper", "london", "period piece", "magic", "magician"],
+ "moji": "🎩"
+ },
+ "trackball": {
+ "unicode": "1F5B2",
+ "unicode_alternates": [],
+ "name": "trackball",
+ "shortname": ":trackball:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["input", "device", "gadget"]
+ },
+ "tractor": {
+ "unicode": "1F69C",
+ "unicode_alternates": [],
+ "name": "tractor",
+ "shortname": ":tractor:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["agriculture", "car", "farming", "vehicle", "tractor", "farm", "construction", "machine", "digger"],
+ "moji": "🚜"
+ },
+ "traffic_light": {
+ "unicode": "1F6A5",
+ "unicode_alternates": [],
+ "name": "horizontal traffic light",
+ "shortname": ":traffic_light:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["traffic", "transportation", "traffic", "light", "stop", "go", "yield", "horizontal"],
+ "moji": "🚥"
+ },
+ "train": {
+ "unicode": "1F68B",
+ "unicode_alternates": [],
+ "name": "Tram Car",
+ "shortname": ":train:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["tram", "rail"]
+ },
+ "train2": {
+ "unicode": "1F686",
+ "unicode_alternates": [],
+ "name": "train",
+ "shortname": ":train2:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "train", "locomotive", "rail"],
+ "moji": "🚆"
+ },
+ "train_diesel": {
+ "unicode": "1F6F2",
+ "unicode_alternates": [],
+ "name": "diesel locomotive",
+ "shortname": ":train_diesel:",
+ "category": "travel_places",
+ "aliases": [":diesel_locomotive:"],
+ "aliases_ascii": [],
+ "keywords": ["train", "transportation", "engine", "rail"]
+ },
+ "tram": {
+ "unicode": "1F68A",
+ "unicode_alternates": [],
+ "name": "tram",
+ "shortname": ":tram:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "vehicle", "tram", "transportation", "transport"],
+ "moji": "🚊"
+ },
+ "triangle_round": {
+ "unicode": "1F6C6",
+ "unicode_alternates": [],
+ "name": "triangle with rounded corners",
+ "shortname": ":triangle_round:",
+ "category": "objects_symbols",
+ "aliases": [":triangle_with_rounded_corners:"],
+ "aliases_ascii": [],
+ "keywords": ["caution", "warning", "alert"]
+ },
+ "triangular_flag_on_post": {
+ "unicode": "1F6A9",
+ "unicode_alternates": [],
+ "name": "triangular flag on post",
+ "shortname": ":triangular_flag_on_post:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["triangle", "triangular", "flag", "golf", "post", "flagpole"],
+ "moji": "🚩"
+ },
+ "triangular_ruler": {
+ "unicode": "1F4D0",
+ "unicode_alternates": [],
+ "name": "triangular ruler",
+ "shortname": ":triangular_ruler:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["architect", "math", "sketch", "stationery"],
+ "moji": "📐"
+ },
+ "trident": {
+ "unicode": "1F531",
+ "unicode_alternates": [],
+ "name": "trident emblem",
+ "shortname": ":trident:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["spear", "weapon"],
+ "moji": "🔱"
+ },
+ "triumph": {
+ "unicode": "1F624",
+ "unicode_alternates": [],
+ "name": "face with look of triumph",
+ "shortname": ":triumph:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "gas", "phew", "triumph", "steam", "breath"],
+ "moji": "😤"
+ },
+ "trolleybus": {
+ "unicode": "1F68E",
+ "unicode_alternates": [],
+ "name": "trolleybus",
+ "shortname": ":trolleybus:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bart", "transportation", "vehicle", "trolley", "bus", "city", "transport", "transportation"],
+ "moji": "🚎"
+ },
+ "trophy": {
+ "unicode": "1F3C6",
+ "unicode_alternates": [],
+ "name": "trophy",
+ "shortname": ":trophy:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["award", "ceremony", "contest", "ftw", "place", "win", "trophy", "first", "show", "place", "win", "reward", "achievement", "medal"],
+ "moji": "🏆"
+ },
+ "tropical_drink": {
+ "unicode": "1F379",
+ "unicode_alternates": [],
+ "name": "tropical drink",
+ "shortname": ":tropical_drink:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["beverage", "tropical", "drink", "mixed", "pineapple", "coconut", "pina", "fruit", "umbrella"],
+ "moji": "🍹"
+ },
+ "tropical_fish": {
+ "unicode": "1F420",
+ "unicode_alternates": [],
+ "name": "tropical fish",
+ "shortname": ":tropical_fish:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "swim"],
+ "moji": "🐠"
+ },
+ "truck": {
+ "unicode": "1F69A",
+ "unicode_alternates": [],
+ "name": "delivery truck",
+ "shortname": ":truck:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["cars", "transportation", "truck", "delivery", "package"],
+ "moji": "🚚"
+ },
+ "trumpet": {
+ "unicode": "1F3BA",
+ "unicode_alternates": [],
+ "name": "trumpet",
+ "shortname": ":trumpet:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["brass", "music", "trumpet", "brass", "music", "instrument"],
+ "moji": "🎺"
+ },
+ "tulip": {
+ "unicode": "1F337",
+ "unicode_alternates": [],
+ "name": "tulip",
+ "shortname": ":tulip:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["flowers", "nature", "plant", "tulip", "flower", "bulb", "spring", "easter"],
+ "moji": "🌷"
+ },
+ "turned_ok_hand": {
+ "unicode": "1F58F",
+ "unicode_alternates": [],
+ "name": "turned ok hand sign",
+ "shortname": ":turned_ok_hand:",
+ "category": "people",
+ "aliases": [":turned_ok_hand_sign:"],
+ "aliases_ascii": [],
+ "keywords": ["perfect", "okay"]
+ },
+ "turtle": {
+ "unicode": "1F422",
+ "unicode_alternates": [],
+ "name": "turtle",
+ "shortname": ":turtle:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "slow", "turtle", "shell", "tortoise", "chelonian", "reptile", "slow", "snap", "steady"],
+ "moji": "🐢"
+ },
+ "twisted_rightwards_arrows": {
+ "unicode": "1F500",
+ "unicode_alternates": [],
+ "name": "twisted rightwards arrows",
+ "shortname": ":twisted_rightwards_arrows:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "🔀"
+ },
+ "two": {
+ "moji": "2️⃣",
+ "unicode": "0032-20E3",
+ "unicode_alternates": ["0032-FE0F-20E3"],
+ "name": "digit two",
+ "shortname": ":two:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["2", "blue-square", "numbers", "prime"]
+ },
+ "two_hearts": {
+ "unicode": "1F495",
+ "unicode_alternates": [],
+ "name": "two hearts",
+ "shortname": ":two_hearts:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "heart", "hearts", "two", "love", "emotion"],
+ "moji": "💕"
+ },
+ "two_men_holding_hands": {
+ "unicode": "1F46C",
+ "unicode_alternates": [],
+ "name": "two men holding hands",
+ "shortname": ":two_men_holding_hands:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bromance", "couple", "friends", "like", "love", "men", "gay", "homosexual", "friends", "hands", "holding", "team", "unity"],
+ "moji": "👬"
+ },
+ "two_women_holding_hands": {
+ "unicode": "1F46D",
+ "unicode_alternates": [],
+ "name": "two women holding hands",
+ "shortname": ":two_women_holding_hands:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["couple", "female", "friends", "like", "love", "women", "hands", "girlfriends", "friends", "sisters", "mother", "daughter", "gay", "homosexual", "couple", "unity"],
+ "moji": "👭"
+ },
+ "u5272": {
+ "unicode": "1F239",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-5272",
+ "shortname": ":u5272:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "cut", "divide", "kanji", "pink"],
+ "moji": "🈹"
+ },
+ "u5408": {
+ "unicode": "1F234",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-5408",
+ "shortname": ":u5408:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "japanese", "join", "kanji"],
+ "moji": "🈴"
+ },
+ "u55b6": {
+ "unicode": "1F23A",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-55b6",
+ "shortname": ":u55b6:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japanese", "opening hours"],
+ "moji": "🈺"
+ },
+ "u6307": {
+ "unicode": "1F22F",
+ "unicode_alternates": ["1F22F-FE0F"],
+ "name": "squared cjk unified ideograph-6307",
+ "shortname": ":u6307:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "green-square", "kanji", "point"],
+ "moji": "🈯"
+ },
+ "u6708": {
+ "unicode": "1F237",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-6708",
+ "shortname": ":u6708:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "japanese", "kanji", "moon", "orange-square"],
+ "moji": "🈷"
+ },
+ "u6709": {
+ "unicode": "1F236",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-6709",
+ "shortname": ":u6709:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "have", "kanji", "orange-square"],
+ "moji": "🈶"
+ },
+ "u6e80": {
+ "unicode": "1F235",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-6e80",
+ "shortname": ":u6e80:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "full", "japanese", "kanji", "red-square"],
+ "moji": "🈵"
+ },
+ "u7121": {
+ "unicode": "1F21A",
+ "unicode_alternates": ["1F21A-FE0F"],
+ "name": "squared cjk unified ideograph-7121",
+ "shortname": ":u7121:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "japanese", "kanji", "no", "nothing", "orange-square"],
+ "moji": "🈚"
+ },
+ "u7533": {
+ "unicode": "1F238",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-7533",
+ "shortname": ":u7533:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "japanese", "kanji"],
+ "moji": "🈸"
+ },
+ "u7981": {
+ "unicode": "1F232",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-7981",
+ "shortname": ":u7981:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "forbidden", "japanese", "kanji", "limit", "restricted"],
+ "moji": "🈲"
+ },
+ "u7a7a": {
+ "unicode": "1F233",
+ "unicode_alternates": [],
+ "name": "squared cjk unified ideograph-7a7a",
+ "shortname": ":u7a7a:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["chinese", "empty", "japanese", "kanji"],
+ "moji": "🈳"
+ },
+ "umbrella": {
+ "unicode": "2614",
+ "unicode_alternates": ["2614-FE0F"],
+ "name": "umbrella with rain drops",
+ "shortname": ":umbrella:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["rain", "weather"],
+ "moji": "☔"
+ },
+ "unamused": {
+ "unicode": "1F612",
+ "unicode_alternates": [],
+ "name": "unamused face",
+ "shortname": ":unamused:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["bored", "face", "indifference", "serious", "straight face", "unamused", "not amused", "depressed", "unhappy", "disapprove", "lame"],
+ "moji": "😒"
+ },
+ "underage": {
+ "unicode": "1F51E",
+ "unicode_alternates": [],
+ "name": "no one under eighteen symbol",
+ "shortname": ":underage:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["18", "drink", "night", "pub"],
+ "moji": "🔞"
+ },
+ "unlock": {
+ "unicode": "1F513",
+ "unicode_alternates": [],
+ "name": "open lock",
+ "shortname": ":unlock:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["privacy", "security"],
+ "moji": "🔓"
+ },
+ "up": {
+ "unicode": "1F199",
+ "unicode_alternates": [],
+ "name": "squared up with exclamation mark",
+ "shortname": ":up:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square"],
+ "moji": "🆙"
+ },
+ "v": {
+ "unicode": "270C",
+ "unicode_alternates": ["270C-FE0F"],
+ "name": "victory hand",
+ "shortname": ":v:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fingers", "hand", "ohyeah", "peace", "two", "victory"],
+ "moji": "✌"
+ },
+ "vertical_traffic_light": {
+ "unicode": "1F6A6",
+ "unicode_alternates": [],
+ "name": "vertical traffic light",
+ "shortname": ":vertical_traffic_light:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["transportation", "traffic", "light", "stop", "go", "yield", "vertical"],
+ "moji": "🚦"
+ },
+ "vhs": {
+ "unicode": "1F4FC",
+ "unicode_alternates": [],
+ "name": "videocassette",
+ "shortname": ":vhs:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["oldschool", "record", "video"],
+ "moji": "📼"
+ },
+ "vibration_mode": {
+ "unicode": "1F4F3",
+ "unicode_alternates": [],
+ "name": "vibration mode",
+ "shortname": ":vibration_mode:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["orange-square", "phone"],
+ "moji": "📳"
+ },
+ "video_camera": {
+ "unicode": "1F4F9",
+ "unicode_alternates": [],
+ "name": "video camera",
+ "shortname": ":video_camera:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["film", "record"],
+ "moji": "📹"
+ },
+ "video_game": {
+ "unicode": "1F3AE",
+ "unicode_alternates": [],
+ "name": "video game",
+ "shortname": ":video_game:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["PS4", "console", "controller", "play", "video", "game", "console", "controller", "nintendo", "xbox", "playstation"],
+ "moji": "🎮"
+ },
+ "violin": {
+ "unicode": "1F3BB",
+ "unicode_alternates": [],
+ "name": "violin",
+ "shortname": ":violin:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["instrument", "music", "violin", "fiddle", "music", "instrument"],
+ "moji": "🎻"
+ },
+ "virgo": {
+ "unicode": "264D",
+ "unicode_alternates": ["264D-FE0F"],
+ "name": "virgo",
+ "shortname": ":virgo:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sign", "virgo", "maiden", "astrology", "greek", "constellation", "stars", "zodiac", "sign", "zodiac", "horoscope"],
+ "moji": "♍"
+ },
+ "volcano": {
+ "unicode": "1F30B",
+ "unicode_alternates": [],
+ "name": "volcano",
+ "shortname": ":volcano:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "photo", "volcano", "lava", "magma", "hot", "explode"],
+ "moji": "🌋"
+ },
+ "vs": {
+ "unicode": "1F19A",
+ "unicode_alternates": [],
+ "name": "squared vs",
+ "shortname": ":vs:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["orange-square", "words"],
+ "moji": "🆚"
+ },
+ "vulcan": {
+ "unicode": "1F596",
+ "unicode_alternates": [],
+ "name": "raised hand with part between middle and ring fingers",
+ "shortname": ":vulcan:",
+ "category": "people",
+ "aliases": [":raised_hand_with_part_between_middle_and_ring_fingers:"],
+ "aliases_ascii": [],
+ "keywords": ["vulcan", "spock", "leonard", "nimoy", "star trek", "live long"]
+ },
+ "walking": {
+ "unicode": "1F6B6",
+ "unicode_alternates": [],
+ "name": "pedestrian",
+ "shortname": ":walking:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["human", "man", "walk", "pedestrian", "stroll", "stride", "foot", "feet"],
+ "moji": "🚶"
+ },
+ "waning_crescent_moon": {
+ "unicode": "1F318",
+ "unicode_alternates": [],
+ "name": "waning crescent moon symbol",
+ "shortname": ":waning_crescent_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "crescent", "waning", "sky", "night", "cheese", "phase"],
+ "moji": "🌘"
+ },
+ "waning_gibbous_moon": {
+ "unicode": "1F316",
+ "unicode_alternates": [],
+ "name": "waning gibbous moon symbol",
+ "shortname": ":waning_gibbous_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "waning", "gibbous", "sky", "night", "cheese", "phase"],
+ "moji": "🌖"
+ },
+ "warning": {
+ "unicode": "26A0",
+ "unicode_alternates": ["26A0-FE0F"],
+ "name": "warning sign",
+ "shortname": ":warning:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["exclamation", "wip"],
+ "moji": "⚠"
+ },
+ "wastebasket": {
+ "unicode": "1F5D1",
+ "unicode_alternates": [],
+ "name": "wastebasket",
+ "shortname": ":wastebasket:",
+ "category": "objects_symbols",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["trash", "garbage", "dispose"]
+ },
+ "watch": {
+ "unicode": "231A",
+ "unicode_alternates": ["231A-FE0F"],
+ "name": "watch",
+ "shortname": ":watch:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "time"],
+ "moji": "⌚"
+ },
+ "water_buffalo": {
+ "unicode": "1F403",
+ "unicode_alternates": [],
+ "name": "water buffalo",
+ "shortname": ":water_buffalo:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "cow", "nature", "ox", "water", "buffalo", "asia", "bovine", "milk", "dairy"],
+ "moji": "🐃"
+ },
+ "watermelon": {
+ "unicode": "1F349",
+ "unicode_alternates": [],
+ "name": "watermelon",
+ "shortname": ":watermelon:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["food", "fruit", "melon", "watermelon", "summer", "fruit", "large"],
+ "moji": "🍉"
+ },
+ "wave": {
+ "unicode": "1F44B",
+ "unicode_alternates": [],
+ "name": "waving hand sign",
+ "shortname": ":wave:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["farewell", "gesture", "goodbye", "hands", "solong"],
+ "moji": "👋"
+ },
+ "wavy_dash": {
+ "unicode": "3030",
+ "unicode_alternates": [],
+ "name": "wavy dash",
+ "shortname": ":wavy_dash:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["draw", "line"],
+ "moji": "〰"
+ },
+ "waxing_crescent_moon": {
+ "unicode": "1F312",
+ "unicode_alternates": [],
+ "name": "waxing crescent moon symbol",
+ "shortname": ":waxing_crescent_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature", "moon", "waxing", "sky", "night", "cheese", "phase"],
+ "moji": "🌒"
+ },
+ "waxing_gibbous_moon": {
+ "unicode": "1F314",
+ "unicode_alternates": [],
+ "name": "waxing gibbous moon symbol",
+ "shortname": ":waxing_gibbous_moon:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["nature"],
+ "moji": "🌔"
+ },
+ "wc": {
+ "unicode": "1F6BE",
+ "unicode_alternates": [],
+ "name": "water closet",
+ "shortname": ":wc:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "restroom", "toilet", "water", "closet", "toilet", "bathroom", "throne", "porcelain", "waste", "flush", "plumbing"],
+ "moji": "🚾"
+ },
+ "weary": {
+ "unicode": "1F629",
+ "unicode_alternates": [],
+ "name": "weary face",
+ "shortname": ":weary:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "frustrated", "sad", "sleepy", "tired", "weary", "sleepy", "tired", "tiredness", "study", "finals", "school", "exhausted"],
+ "moji": "😩"
+ },
+ "wedding": {
+ "unicode": "1F492",
+ "unicode_alternates": [],
+ "name": "wedding",
+ "shortname": ":wedding:",
+ "category": "places",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "bride", "couple", "groom", "like", "love", "marriage"],
+ "moji": "💒"
+ },
+ "whale": {
+ "unicode": "1F433",
+ "unicode_alternates": [],
+ "name": "spouting whale",
+ "shortname": ":whale:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "ocean", "sea"],
+ "moji": "🐳"
+ },
+ "whale2": {
+ "unicode": "1F40B",
+ "unicode_alternates": [],
+ "name": "whale",
+ "shortname": ":whale2:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature", "ocean", "sea", "whale", "blubber", "bloated", "fat", "large", "massive"],
+ "moji": "🐋"
+ },
+ "wheelchair": {
+ "unicode": "267F",
+ "unicode_alternates": ["267F-FE0F"],
+ "name": "wheelchair symbol",
+ "shortname": ":wheelchair:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "disabled"],
+ "moji": "♿"
+ },
+ "white_check_mark": {
+ "unicode": "2705",
+ "unicode_alternates": [],
+ "name": "white heavy check mark",
+ "shortname": ":white_check_mark:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["agree", "green-square", "ok"],
+ "moji": "✅"
+ },
+ "white_circle": {
+ "unicode": "26AA",
+ "unicode_alternates": ["26AA-FE0F"],
+ "name": "medium white circle",
+ "shortname": ":white_circle:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "⚪"
+ },
+ "white_flower": {
+ "unicode": "1F4AE",
+ "unicode_alternates": [],
+ "name": "white flower",
+ "shortname": ":white_flower:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["japanese", "white", "flower", "teacher", "school", "grade", "score", "brilliance", "intelligence", "homework", "student", "assignment", "praise"],
+ "moji": "💮"
+ },
+ "white_large_square": {
+ "unicode": "2B1C",
+ "unicode_alternates": ["2B1C-FE0F"],
+ "name": "white large square",
+ "shortname": ":white_large_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "⬜"
+ },
+ "white_medium_small_square": {
+ "unicode": "25FD",
+ "unicode_alternates": ["25FD-FE0F"],
+ "name": "white medium small square",
+ "shortname": ":white_medium_small_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "◽"
+ },
+ "white_medium_square": {
+ "unicode": "25FB",
+ "unicode_alternates": ["25FB-FE0F"],
+ "name": "white medium square",
+ "shortname": ":white_medium_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "◻"
+ },
+ "white_small_square": {
+ "unicode": "25AB",
+ "unicode_alternates": ["25AB-FE0F"],
+ "name": "white small square",
+ "shortname": ":white_small_square:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "▫"
+ },
+ "white_square_button": {
+ "unicode": "1F533",
+ "unicode_alternates": [],
+ "name": "white square button",
+ "shortname": ":white_square_button:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["shape"],
+ "moji": "🔳"
+ },
+ "wind_blowing_face": {
+ "unicode": "1F32C",
+ "unicode_alternates": [],
+ "name": "wind blowing face",
+ "shortname": ":wind_blowing_face:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["mother", "nature"]
+ },
+ "wind_chime": {
+ "unicode": "1F390",
+ "unicode_alternates": [],
+ "name": "wind chime",
+ "shortname": ":wind_chime:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["ding", "nature", "wind", "chime", "bell", "fūrin", "instrument", "music", "spirits", "soothing", "protective", "spiritual", "sound"],
+ "moji": "🎐"
+ },
+ "wine_glass": {
+ "unicode": "1F377",
+ "unicode_alternates": [],
+ "name": "wine glass",
+ "shortname": ":wine_glass:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["alcohol", "beverage", "booze", "bottle", "drink", "drunk", "fermented", "glass", "grapes", "tasting", "wine", "winery"],
+ "moji": "🍷"
+ },
+ "wink": {
+ "unicode": "1F609",
+ "unicode_alternates": [],
+ "name": "winking face",
+ "shortname": ":wink:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [";)", ";-)", "*-)", "*)", ";-]", ";]", ";D", ";^)"],
+ "keywords": ["face", "happy", "mischievous", "secret", "wink", "winking", "friendly", "joke"],
+ "moji": "😉"
+ },
+ "wolf": {
+ "unicode": "1F43A",
+ "unicode_alternates": [],
+ "name": "wolf face",
+ "shortname": ":wolf:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["animal", "nature"],
+ "moji": "🐺"
+ },
+ "woman": {
+ "unicode": "1F469",
+ "unicode_alternates": [],
+ "name": "woman",
+ "shortname": ":woman:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["female", "girls"],
+ "moji": "👩"
+ },
+ "womans_clothes": {
+ "unicode": "1F45A",
+ "unicode_alternates": [],
+ "name": "womans clothes",
+ "shortname": ":womans_clothes:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["fashion", "woman", "clothing", "clothes", "blouse", "shirt", "wardrobe", "breasts", "cleavage", "shopping", "shop", "dressing", "dressed"],
+ "moji": "👚"
+ },
+ "womans_hat": {
+ "unicode": "1F452",
+ "unicode_alternates": [],
+ "name": "womans hat",
+ "shortname": ":womans_hat:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["accessories", "fashion", "female"],
+ "moji": "👒"
+ },
+ "womens": {
+ "unicode": "1F6BA",
+ "unicode_alternates": [],
+ "name": "womens symbol",
+ "shortname": ":womens:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["purple-square", "woman", "bathroom", "restroom", "sign", "girl", "female", "avatar"],
+ "moji": "🚺"
+ },
+ "worried": {
+ "unicode": "1F61F",
+ "unicode_alternates": [],
+ "name": "worried face",
+ "shortname": ":worried:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["concern", "face", "nervous", "worried", "anxious", "distressed", "nervous", "tense"],
+ "moji": "😟"
+ },
+ "wrench": {
+ "unicode": "1F527",
+ "unicode_alternates": [],
+ "name": "wrench",
+ "shortname": ":wrench:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["diy", "ikea", "tools"],
+ "moji": "🔧"
+ },
+ "writing_hand": {
+ "unicode": "1F58E",
+ "unicode_alternates": [],
+ "name": "left writing hand",
+ "shortname": ":writing_hand:",
+ "category": "people",
+ "aliases": [":left_writing_hand:"],
+ "aliases_ascii": [],
+ "keywords": ["write", "sign", "signature", "draw"]
+ },
+ "x": {
+ "unicode": "274C",
+ "unicode_alternates": [],
+ "name": "cross mark",
+ "shortname": ":x:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["delete", "no", "remove"],
+ "moji": "❌"
+ },
+ "yellow_heart": {
+ "unicode": "1F49B",
+ "unicode_alternates": [],
+ "name": "yellow heart",
+ "shortname": ":yellow_heart:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["affection", "like", "love", "valentines", "yellow", "gold", "heart", "love", "friendship", "happy", "happiness", "trust", "compassionate", "respectful", "honest", "caring", "selfless"],
+ "moji": "💛"
+ },
+ "yen": {
+ "unicode": "1F4B4",
+ "unicode_alternates": [],
+ "name": "banknote with yen sign",
+ "shortname": ":yen:",
+ "category": "objects",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["currency", "dollar", "japanese", "money", "yen", "japan", "japanese", "banknote", "money", "currency", "paper", "cash", "bill"],
+ "moji": "💴"
+ },
+ "yum": {
+ "unicode": "1F60B",
+ "unicode_alternates": [],
+ "name": "face savouring delicious food",
+ "shortname": ":yum:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["face", "happy", "joy", "smile", "tongue", "delicious", "savoring", "food", "eat", "yummy", "yum", "tasty", "savory"],
+ "moji": "😋"
+ },
+ "zap": {
+ "unicode": "26A1",
+ "unicode_alternates": ["26A1-FE0F"],
+ "name": "high voltage sign",
+ "shortname": ":zap:",
+ "category": "nature",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["lightning bolt", "thunder", "weather"],
+ "moji": "⚡"
+ },
+ "zero": {
+ "moji": "0️⃣",
+ "unicode": "0030-20E3",
+ "unicode_alternates": ["0030-FE0F-20E3"],
+ "name": "digit zero",
+ "shortname": ":zero:",
+ "category": "other",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["blue-square", "null", "numbers"]
+ },
+ "zzz": {
+ "unicode": "1F4A4",
+ "unicode_alternates": [],
+ "name": "sleeping symbol",
+ "shortname": ":zzz:",
+ "category": "emoticons",
+ "aliases": [],
+ "aliases_ascii": [],
+ "keywords": ["sleepy", "tired"],
+ "moji": "💤"
+ }
+}
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index b1cd80bdf65..f8511ac5f5c 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -67,9 +67,10 @@ module API
expose :shared_runners_enabled
expose :creator_id
expose :namespace
- expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
+ expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ |project, options| project.forked? }
expose :avatar_url
expose :star_count, :forks_count
+ expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? }
end
class ProjectMember < UserBasic
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index bdf4b77596e..a9e0960872a 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -25,7 +25,7 @@ module API
@projects = current_user.authorized_projects
@projects = filter_projects(@projects)
@projects = paginate @projects
- present @projects, with: Entities::Project
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
end
# Get an owned projects list for authenticated user
@@ -36,6 +36,17 @@ module API
@projects = current_user.owned_projects
@projects = filter_projects(@projects)
@projects = paginate @projects
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
+ end
+
+ # Gets starred project for the authenticated user
+ #
+ # Example Request:
+ # GET /projects/starred
+ get '/starred' do
+ @projects = current_user.starred_projects
+ @projects = filter_projects(@projects)
+ @projects = paginate @projects
present @projects, with: Entities::Project
end
@@ -48,7 +59,7 @@ module API
@projects = Project.all
@projects = filter_projects(@projects)
@projects = paginate @projects
- present @projects, with: Entities::Project
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
end
# Get a single project
diff --git a/lib/award_emoji.rb b/lib/award_emoji.rb
index 3825f4650be..783fcfb61ad 100644
--- a/lib/award_emoji.rb
+++ b/lib/award_emoji.rb
@@ -1,35 +1,4 @@
class AwardEmoji
- ALIASES = {
- pout: "rage",
- satisfied: "laughing",
- hankey: "shit",
- poop: "shit",
- collision: "boom",
- thumbsup: "+1",
- thumbsdown: "-1",
- punch: "facepunch",
- raised_hand: "hand",
- running: "runner",
- ng_woman: "no_good",
- shoe: "mans_shoe",
- tshirt: "shirt",
- honeybee: "bee",
- flipper: "dolphin",
- paw_prints: "feet",
- waxing_gibbous_moon: "moon",
- telephone: "phone",
- knife: "hocho",
- envelope: "email",
- pencil: "memo",
- open_book: "book",
- sailboat: "boat",
- red_car: "car",
- lantern: "izakaya_lantern",
- uk: "gb",
- heavy_exclamation_mark: "exclamation",
- squirrel: "shipit"
- }.with_indifferent_access
-
CATEGORIES = {
other: "Other",
objects: "Objects",
@@ -46,17 +15,15 @@ class AwardEmoji
}.with_indifferent_access
def self.normilize_emoji_name(name)
- ALIASES[name] || name
+ aliases[name] || name
end
def self.emoji_by_category
unless @emoji_by_category
@emoji_by_category = {}
- emojis_added = []
- Emoji.emojis.each do |emoji_name, data|
- next if emojis_added.include?(data["name"])
- emojis_added << data["name"]
+ emojis.each do |emoji_name, data|
+ data["name"] = emoji_name
@emoji_by_category[data["category"]] ||= []
@emoji_by_category[data["category"]] << data
@@ -67,4 +34,18 @@ class AwardEmoji
@emoji_by_category
end
+
+ def self.emojis
+ @emojis ||= begin
+ json_path = File.join(Rails.root, 'fixtures', 'emojis', 'index.json' )
+ JSON.parse(File.read(json_path))
+ end
+ end
+
+ def self.aliases
+ @aliases ||= begin
+ json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json' )
+ JSON.parse(File.read(json_path))
+ end
+ end
end
diff --git a/lib/banzai.rb b/lib/banzai.rb
new file mode 100644
index 00000000000..093382261ae
--- /dev/null
+++ b/lib/banzai.rb
@@ -0,0 +1,13 @@
+module Banzai
+ def self.render(text, context = {})
+ Renderer.render(text, context)
+ end
+
+ def self.render_result(text, context = {})
+ Renderer.render_result(text, context)
+ end
+
+ def self.post_process(html, context)
+ Renderer.post_process(html, context)
+ end
+end
diff --git a/lib/banzai/cross_project_reference.rb b/lib/banzai/cross_project_reference.rb
new file mode 100644
index 00000000000..ba2866e1efa
--- /dev/null
+++ b/lib/banzai/cross_project_reference.rb
@@ -0,0 +1,22 @@
+require 'banzai'
+
+module Banzai
+ # Common methods for ReferenceFilters that support an optional cross-project
+ # reference.
+ module CrossProjectReference
+ # Given a cross-project reference string, get the Project record
+ #
+ # Defaults to value of `context[:project]` if:
+ # * No reference is given OR
+ # * Reference given doesn't exist
+ #
+ # ref - String reference.
+ #
+ # Returns a Project, or nil if the reference can't be found
+ def project_from_ref(ref)
+ return context[:project] unless ref
+
+ Project.find_with_namespace(ref)
+ end
+ end
+end
diff --git a/lib/banzai/filter.rb b/lib/banzai/filter.rb
new file mode 100644
index 00000000000..fd4fe024252
--- /dev/null
+++ b/lib/banzai/filter.rb
@@ -0,0 +1,10 @@
+require 'active_support/core_ext/string/output_safety'
+require 'banzai'
+
+module Banzai
+ module Filter
+ def self.[](name)
+ const_get("#{name.to_s.camelize}Filter")
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 9488e980c08..bdaa4721b4b 100644
--- a/lib/gitlab/markdown/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# Issues, Merge Requests, Snippets, Commits and Commit Ranges share
# similar functionality in reference filtering.
class AbstractReferenceFilter < ReferenceFilter
diff --git a/lib/gitlab/markdown/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb
index c37c3bc55bf..da4ee80c1b5 100644
--- a/lib/gitlab/markdown/filter/autolink_filter.rb
+++ b/lib/banzai/filter/autolink_filter.rb
@@ -1,9 +1,9 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
require 'uri'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML Filter for auto-linking URLs in HTML.
#
# Based on HTML::Pipeline::AutolinkFilter
diff --git a/lib/gitlab/markdown/filter/commit_range_reference_filter.rb b/lib/banzai/filter/commit_range_reference_filter.rb
index 36b3258ef76..e67cd45ab9b 100644
--- a/lib/gitlab/markdown/filter/commit_range_reference_filter.rb
+++ b/lib/banzai/filter/commit_range_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces commit range references with links.
#
# This filter supports cross-project references.
diff --git a/lib/gitlab/markdown/filter/commit_reference_filter.rb b/lib/banzai/filter/commit_reference_filter.rb
index e3066a89b04..9e57608b483 100644
--- a/lib/gitlab/markdown/filter/commit_reference_filter.rb
+++ b/lib/banzai/filter/commit_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces commit references with links.
#
# This filter supports cross-project references.
diff --git a/lib/gitlab/markdown/filter/emoji_filter.rb b/lib/banzai/filter/emoji_filter.rb
index da10e4d3760..86838e1483c 100644
--- a/lib/gitlab/markdown/filter/emoji_filter.rb
+++ b/lib/banzai/filter/emoji_filter.rb
@@ -1,10 +1,10 @@
require 'action_controller'
-require 'gitlab/markdown'
+require 'banzai'
require 'gitlab_emoji'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces :emoji: with images.
#
# Based on HTML::Pipeline::EmojiFilter
diff --git a/lib/gitlab/markdown/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb
index 14bdf5521fc..f5942740cd6 100644
--- a/lib/gitlab/markdown/filter/external_issue_reference_filter.rb
+++ b/lib/banzai/filter/external_issue_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces external issue tracker references with links.
# References are ignored if the project doesn't use an external issue
# tracker.
@@ -23,6 +23,18 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ project = Project.find(node.attr("data-project")) rescue nil
+ return unless project
+
+ id = node.attr("data-external-issue")
+ external_issue = ExternalIssue.new(id, project)
+
+ return unless external_issue
+
+ { external_issue: external_issue }
+ end
+
def call
# Early return if the project isn't using an external tracker
return doc if project.nil? || project.default_issues_tracker?
@@ -46,12 +58,14 @@ module Gitlab
def issue_link_filter(text, link_text: nil)
project = context[:project]
- self.class.references_in(text) do |match, issue|
- url = url_for_issue(issue, project, only_path: context[:only_path])
+ self.class.references_in(text) do |match, id|
+ ExternalIssue.new(id, project)
+
+ url = url_for_issue(id, project, only_path: context[:only_path])
title = escape_once("Issue in #{project.external_issue_tracker.title}")
klass = reference_class(:issue)
- data = data_attribute(project: project.id)
+ data = data_attribute(project: project.id, external_issue: id)
text = link_text || match
diff --git a/lib/gitlab/markdown/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb
index e09dfcb83c8..ac87b9820af 100644
--- a/lib/gitlab/markdown/filter/external_link_filter.rb
+++ b/lib/banzai/filter/external_link_filter.rb
@@ -1,8 +1,8 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML Filter to add a `rel="nofollow"` attribute to external links
#
class ExternalLinkFilter < HTML::Pipeline::Filter
diff --git a/lib/gitlab/markdown/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb
index 1ed69e2f431..51180cb901a 100644
--- a/lib/gitlab/markdown/filter/issue_reference_filter.rb
+++ b/lib/banzai/filter/issue_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces issue references with links. References to
# issues that do not exist are ignored.
#
diff --git a/lib/gitlab/markdown/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index a2026eecaeb..07bac2dd7fd 100644
--- a/lib/gitlab/markdown/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces label references with links.
class LabelReferenceFilter < ReferenceFilter
# Public: Find label references in text
diff --git a/lib/gitlab/markdown/filter/markdown_filter.rb b/lib/banzai/filter/markdown_filter.rb
index 921e2a0794e..d09cf41df39 100644
--- a/lib/gitlab/markdown/filter/markdown_filter.rb
+++ b/lib/banzai/filter/markdown_filter.rb
@@ -1,9 +1,12 @@
-module Gitlab
- module Markdown
+require 'banzai'
+require 'html/pipeline/filter'
+
+module Banzai
+ module Filter
class MarkdownFilter < HTML::Pipeline::TextFilter
def initialize(text, context = nil, result = nil)
super text, context, result
- @text = @text.gsub "\r", ''
+ @text = @text.delete "\r"
end
def call
@@ -11,8 +14,8 @@ module Gitlab
html.rstrip!
html
end
-
- private
+
+ private
def self.redcarpet_options
# https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
diff --git a/lib/gitlab/markdown/filter/merge_request_reference_filter.rb b/lib/banzai/filter/merge_request_reference_filter.rb
index 2eb77c46da7..755b946a34b 100644
--- a/lib/gitlab/markdown/filter/merge_request_reference_filter.rb
+++ b/lib/banzai/filter/merge_request_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces merge request references with links. References
# to merge requests that do not exist are ignored.
#
diff --git a/lib/gitlab/markdown/filter/redactor_filter.rb b/lib/banzai/filter/redactor_filter.rb
index 33ef7ce18b5..89e7a79789a 100644
--- a/lib/gitlab/markdown/filter/redactor_filter.rb
+++ b/lib/banzai/filter/redactor_filter.rb
@@ -1,8 +1,8 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that removes references to records that the current user does
# not have permission to view.
#
@@ -27,7 +27,7 @@ module Gitlab
def user_can_reference?(node)
if node.has_attribute?('data-reference-filter')
reference_type = node.attr('data-reference-filter')
- reference_filter = Gitlab::Markdown.const_get(reference_type)
+ reference_filter = Banzai::Filter.const_get(reference_type)
reference_filter.user_can_reference?(current_user, node, context)
else
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/banzai/filter/reference_filter.rb
index 3b83b8bd8f8..33457a3f361 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/banzai/filter/reference_filter.rb
@@ -1,9 +1,9 @@
require 'active_support/core_ext/string/output_safety'
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# Base class for GitLab Flavored Markdown reference filters.
#
# References within <pre>, <code>, <a>, and <style> elements are ignored.
@@ -12,27 +12,6 @@ module Gitlab
# :project (required) - Current project, ignored if reference is cross-project.
# :only_path - Generate path-only links.
class ReferenceFilter < HTML::Pipeline::Filter
- LazyReference = Struct.new(:klass, :ids) do
- def self.load(refs)
- lazy_references, values = refs.partition { |ref| ref.is_a?(self) }
-
- lazy_values = lazy_references.group_by(&:klass).flat_map do |klass, refs|
- ids = refs.flat_map(&:ids)
- klass.where(id: ids)
- end
-
- values + lazy_values
- end
-
- def load
- self.klass.where(id: self.ids)
- end
- end
-
- def self.[](name)
- Markdown.const_get("#{name.to_s.camelize}ReferenceFilter")
- end
-
def self.user_can_reference?(user, node, context)
if node.has_attribute?('data-project')
project_id = node.attr('data-project').to_i
diff --git a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb b/lib/banzai/filter/reference_gatherer_filter.rb
index 62f241b4967..855f238ac1e 100644
--- a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb
+++ b/lib/banzai/filter/reference_gatherer_filter.rb
@@ -1,8 +1,8 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that gathers all referenced records that the current user has
# permission to view.
#
@@ -20,7 +20,7 @@ module Gitlab
gather_references(node)
end
- load_lazy_references unless context[:load_lazy_references] == false
+ load_lazy_references unless ReferenceExtractor.lazy?
doc
end
@@ -31,7 +31,7 @@ module Gitlab
return unless node.has_attribute?('data-reference-filter')
reference_type = node.attr('data-reference-filter')
- reference_filter = Gitlab::Markdown.const_get(reference_type)
+ reference_filter = Banzai::Filter.const_get(reference_type)
return if context[:reference_filter] && reference_filter != context[:reference_filter]
@@ -47,11 +47,10 @@ module Gitlab
end
end
- # Will load all references of one type using one query.
def load_lazy_references
refs = result[:references]
refs.each do |type, values|
- refs[type] = ReferenceFilter::LazyReference.load(values)
+ refs[type] = ReferenceExtractor.lazily(values)
end
end
diff --git a/lib/gitlab/markdown/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index 81f60120fcd..5a081125f21 100644
--- a/lib/gitlab/markdown/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -1,9 +1,9 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
require 'uri'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that "fixes" relative links to files in a repository.
#
# Context options:
diff --git a/lib/gitlab/markdown/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index cf153f30622..d03e3ae4b3c 100644
--- a/lib/gitlab/markdown/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -1,9 +1,9 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
require 'html/pipeline/sanitization_filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# Sanitize HTML
#
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
diff --git a/lib/gitlab/markdown/filter/snippet_reference_filter.rb b/lib/banzai/filter/snippet_reference_filter.rb
index f7bd07c2a34..1ad5df96f85 100644
--- a/lib/gitlab/markdown/filter/snippet_reference_filter.rb
+++ b/lib/banzai/filter/snippet_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces snippet references with links. References to
# snippets that do not exist are ignored.
#
diff --git a/lib/gitlab/markdown/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 8597e02f0de..c889cc1e97c 100644
--- a/lib/gitlab/markdown/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -1,9 +1,9 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
require 'rouge/plugins/redcarpet'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML Filter to highlight fenced code blocks
#
class SyntaxHighlightFilter < HTML::Pipeline::Filter
diff --git a/lib/gitlab/markdown/filter/table_of_contents_filter.rb b/lib/banzai/filter/table_of_contents_filter.rb
index bbb3bf7fc8b..9b3e67206d5 100644
--- a/lib/gitlab/markdown/filter/table_of_contents_filter.rb
+++ b/lib/banzai/filter/table_of_contents_filter.rb
@@ -1,8 +1,8 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that adds an anchor child element to all Headers in a
# document, so that they can be linked to.
#
@@ -31,7 +31,7 @@ module Gitlab
id = text.downcase
id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
- id.gsub!(' ', '-') # replace spaces with dash
+ id.tr!(' ', '-') # replace spaces with dash
id.squeeze!('-') # replace multiple dashes with one
uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
diff --git a/lib/gitlab/markdown/filter/task_list_filter.rb b/lib/banzai/filter/task_list_filter.rb
index 2f133ae8500..bdf7c2ebdfc 100644
--- a/lib/gitlab/markdown/filter/task_list_filter.rb
+++ b/lib/banzai/filter/task_list_filter.rb
@@ -1,8 +1,8 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'task_list/filter'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# Work around a bug in the default TaskList::Filter that adds a `task-list`
# class to every list element, regardless of whether or not it contains a
# task list.
diff --git a/lib/gitlab/markdown/filter/upload_link_filter.rb b/lib/banzai/filter/upload_link_filter.rb
index fbada73ab86..1a1d0aad8ca 100644
--- a/lib/gitlab/markdown/filter/upload_link_filter.rb
+++ b/lib/banzai/filter/upload_link_filter.rb
@@ -1,9 +1,9 @@
-require 'gitlab/markdown'
+require 'banzai'
require 'html/pipeline/filter'
require 'uri'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that "fixes" relative upload links to files.
# Context options:
# :project (required) - Current project
diff --git a/lib/gitlab/markdown/filter/user_reference_filter.rb b/lib/banzai/filter/user_reference_filter.rb
index 0a20d9c0347..67c24faf991 100644
--- a/lib/gitlab/markdown/filter/user_reference_filter.rb
+++ b/lib/banzai/filter/user_reference_filter.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Filter
# HTML filter that replaces user or group references with links.
#
# A special `@all` reference is also supported.
diff --git a/lib/banzai/lazy_reference.rb b/lib/banzai/lazy_reference.rb
new file mode 100644
index 00000000000..073ec5d9801
--- /dev/null
+++ b/lib/banzai/lazy_reference.rb
@@ -0,0 +1,27 @@
+require 'banzai'
+
+module Banzai
+ class LazyReference
+ def self.load(refs)
+ lazy_references, values = refs.partition { |ref| ref.is_a?(self) }
+
+ lazy_values = lazy_references.group_by(&:klass).flat_map do |klass, refs|
+ ids = refs.flat_map(&:ids)
+ klass.where(id: ids)
+ end
+
+ values + lazy_values
+ end
+
+ attr_reader :klass, :ids
+
+ def initialize(klass, ids)
+ @klass = klass
+ @ids = Array.wrap(ids).map(&:to_i)
+ end
+
+ def load
+ self.klass.where(id: self.ids)
+ end
+ end
+end
diff --git a/lib/banzai/pipeline.rb b/lib/banzai/pipeline.rb
new file mode 100644
index 00000000000..4e017809d9d
--- /dev/null
+++ b/lib/banzai/pipeline.rb
@@ -0,0 +1,10 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ def self.[](name)
+ name ||= :full
+ const_get("#{name.to_s.camelize}Pipeline")
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/asciidoc_pipeline.rb b/lib/banzai/pipeline/asciidoc_pipeline.rb
new file mode 100644
index 00000000000..5e76a817be5
--- /dev/null
+++ b/lib/banzai/pipeline/asciidoc_pipeline.rb
@@ -0,0 +1,13 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class AsciidocPipeline < BasePipeline
+ def self.filters
+ [
+ Filter::RelativeLinkFilter
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/atom_pipeline.rb b/lib/banzai/pipeline/atom_pipeline.rb
new file mode 100644
index 00000000000..957f352aec5
--- /dev/null
+++ b/lib/banzai/pipeline/atom_pipeline.rb
@@ -0,0 +1,14 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class AtomPipeline < FullPipeline
+ def self.transform_context(context)
+ super(context).merge(
+ only_path: false,
+ xhtml: true
+ )
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/base_pipeline.rb b/lib/banzai/pipeline/base_pipeline.rb
new file mode 100644
index 00000000000..cd30009e5c0
--- /dev/null
+++ b/lib/banzai/pipeline/base_pipeline.rb
@@ -0,0 +1,30 @@
+require 'banzai'
+require 'html/pipeline'
+
+module Banzai
+ module Pipeline
+ class BasePipeline
+ def self.filters
+ []
+ end
+
+ def self.transform_context(context)
+ context
+ end
+
+ def self.html_pipeline
+ @html_pipeline ||= HTML::Pipeline.new(filters)
+ end
+
+ class << self
+ %i(call to_document to_html).each do |meth|
+ define_method(meth) do |text, context|
+ context = transform_context(context)
+
+ html_pipeline.send(meth, text, context)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/combined_pipeline.rb b/lib/banzai/pipeline/combined_pipeline.rb
index 6b08a5e9f72..f3bf1809d18 100644
--- a/lib/gitlab/markdown/combined_pipeline.rb
+++ b/lib/banzai/pipeline/combined_pipeline.rb
@@ -1,10 +1,10 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Pipeline
module CombinedPipeline
def self.new(*pipelines)
- Class.new(Pipeline) do
+ Class.new(BasePipeline) do
const_set :PIPELINES, pipelines
def self.pipelines
diff --git a/lib/gitlab/markdown/pipeline/description_pipeline.rb b/lib/banzai/pipeline/description_pipeline.rb
index 76f6948af8f..94c2cb165a5 100644
--- a/lib/gitlab/markdown/pipeline/description_pipeline.rb
+++ b/lib/banzai/pipeline/description_pipeline.rb
@@ -1,10 +1,10 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Pipeline
class DescriptionPipeline < FullPipeline
def self.transform_context(context)
- super(context).merge(
+ super(context).merge(
# SanitizationFilter
inline_sanitization: true
)
diff --git a/lib/gitlab/markdown/pipeline/email_pipeline.rb b/lib/banzai/pipeline/email_pipeline.rb
index b88cb790270..14356145a35 100644
--- a/lib/gitlab/markdown/pipeline/email_pipeline.rb
+++ b/lib/banzai/pipeline/email_pipeline.rb
@@ -1,10 +1,10 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Pipeline
class EmailPipeline < FullPipeline
def self.transform_context(context)
- super(context).merge(
+ super(context).merge(
only_path: false
)
end
diff --git a/lib/gitlab/markdown/pipeline/full_pipeline.rb b/lib/banzai/pipeline/full_pipeline.rb
index b3b7a3c27c0..72395a5d50e 100644
--- a/lib/gitlab/markdown/pipeline/full_pipeline.rb
+++ b/lib/banzai/pipeline/full_pipeline.rb
@@ -1,7 +1,7 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Pipeline
class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline)
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
new file mode 100644
index 00000000000..38750b55ec7
--- /dev/null
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -0,0 +1,41 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class GfmPipeline < BasePipeline
+ def self.filters
+ @filters ||= [
+ Filter::SyntaxHighlightFilter,
+ Filter::SanitizationFilter,
+
+ Filter::UploadLinkFilter,
+ Filter::EmojiFilter,
+ Filter::TableOfContentsFilter,
+ Filter::AutolinkFilter,
+ Filter::ExternalLinkFilter,
+
+ Filter::UserReferenceFilter,
+ Filter::IssueReferenceFilter,
+ Filter::ExternalIssueReferenceFilter,
+ Filter::MergeRequestReferenceFilter,
+ Filter::SnippetReferenceFilter,
+ Filter::CommitRangeReferenceFilter,
+ Filter::CommitReferenceFilter,
+ Filter::LabelReferenceFilter,
+
+ Filter::TaskListFilter
+ ]
+ end
+
+ def self.transform_context(context)
+ context.merge(
+ only_path: true,
+
+ # EmojiFilter
+ asset_host: Gitlab::Application.config.asset_host,
+ asset_root: Gitlab.config.gitlab.base_url
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/pipeline/note_pipeline.rb b/lib/banzai/pipeline/note_pipeline.rb
index a8bf5f42d8e..89335143852 100644
--- a/lib/gitlab/markdown/pipeline/note_pipeline.rb
+++ b/lib/banzai/pipeline/note_pipeline.rb
@@ -1,10 +1,10 @@
-require 'gitlab/markdown'
+require 'banzai'
-module Gitlab
- module Markdown
+module Banzai
+ module Pipeline
class NotePipeline < FullPipeline
def self.transform_context(context)
- super(context).merge(
+ super(context).merge(
# TableOfContentsFilter
no_header_anchors: true
)
diff --git a/lib/banzai/pipeline/plain_markdown_pipeline.rb b/lib/banzai/pipeline/plain_markdown_pipeline.rb
new file mode 100644
index 00000000000..998fd75daa2
--- /dev/null
+++ b/lib/banzai/pipeline/plain_markdown_pipeline.rb
@@ -0,0 +1,13 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class PlainMarkdownPipeline < BasePipeline
+ def self.filters
+ [
+ Filter::MarkdownFilter
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb
new file mode 100644
index 00000000000..148f24b6ce1
--- /dev/null
+++ b/lib/banzai/pipeline/post_process_pipeline.rb
@@ -0,0 +1,20 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class PostProcessPipeline < BasePipeline
+ def self.filters
+ [
+ Filter::RelativeLinkFilter,
+ Filter::RedactorFilter
+ ]
+ end
+
+ def self.transform_context(context)
+ context.merge(
+ post_process: true
+ )
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/reference_extraction_pipeline.rb b/lib/banzai/pipeline/reference_extraction_pipeline.rb
new file mode 100644
index 00000000000..4f9bc9fcccc
--- /dev/null
+++ b/lib/banzai/pipeline/reference_extraction_pipeline.rb
@@ -0,0 +1,13 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class ReferenceExtractionPipeline < BasePipeline
+ def self.filters
+ [
+ Filter::ReferenceGathererFilter
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb
new file mode 100644
index 00000000000..6725c9039a9
--- /dev/null
+++ b/lib/banzai/pipeline/single_line_pipeline.rb
@@ -0,0 +1,9 @@
+require 'banzai'
+
+module Banzai
+ module Pipeline
+ class SingleLinePipeline < GfmPipeline
+
+ end
+ end
+end
diff --git a/lib/banzai/reference_extractor.rb b/lib/banzai/reference_extractor.rb
new file mode 100644
index 00000000000..2c197d31898
--- /dev/null
+++ b/lib/banzai/reference_extractor.rb
@@ -0,0 +1,55 @@
+require 'banzai'
+
+module Banzai
+ # Extract possible GFM references from an arbitrary String for further processing.
+ class ReferenceExtractor
+ class << self
+ LAZY_KEY = :banzai_reference_extractor_lazy
+
+ def lazy?
+ Thread.current[LAZY_KEY]
+ end
+
+ def lazily(values = nil, &block)
+ return (values || block.call).uniq if lazy?
+
+ begin
+ Thread.current[LAZY_KEY] = true
+
+ values ||= block.call
+
+ Banzai::LazyReference.load(values.uniq).uniq
+ ensure
+ Thread.current[LAZY_KEY] = false
+ end
+ end
+ end
+
+ def initialize
+ @texts = []
+ end
+
+ def analyze(text, context = {})
+ @texts << Renderer.render(text, context)
+ end
+
+ def references(type, context = {})
+ filter = Banzai::Filter["#{type}_reference"]
+
+ context.merge!(
+ pipeline: :reference_extraction,
+
+ # ReferenceGathererFilter
+ reference_filter: filter
+ )
+
+ self.class.lazily do
+ @texts.flat_map do |html|
+ text_context = context.dup
+ result = Renderer.render_result(html, text_context)
+ result[:references][type]
+ end.uniq
+ end
+ end
+ end
+end
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
new file mode 100644
index 00000000000..115ae914524
--- /dev/null
+++ b/lib/banzai/renderer.rb
@@ -0,0 +1,78 @@
+module Banzai
+ module Renderer
+ CACHE_ENABLED = false
+
+ # Convert a Markdown String into an HTML-safe String of HTML
+ #
+ # Note that while the returned HTML will have been sanitized of dangerous
+ # HTML, it may post a risk of information leakage if it's not also passed
+ # through `post_process`.
+ #
+ # Also note that the returned String is always HTML, not XHTML. Views
+ # requiring XHTML, such as Atom feeds, need to call `post_process` on the
+ # result, providing the appropriate `pipeline` option.
+ #
+ # markdown - Markdown String
+ # context - Hash of context options passed to our HTML Pipeline
+ #
+ # Returns an HTML-safe String
+ def self.render(text, context = {})
+ cache_key = context.delete(:cache_key)
+ cache_key = full_cache_key(cache_key, context[:pipeline])
+
+ if cache_key && CACHE_ENABLED
+ Rails.cache.fetch(cache_key) do
+ cacheless_render(text, context)
+ end
+ else
+ cacheless_render(text, context)
+ end
+ end
+
+ def self.render_result(text, context = {})
+ Pipeline[context[:pipeline]].call(text, context)
+ end
+
+ # Perform post-processing on an HTML String
+ #
+ # This method is used to perform state-dependent changes to a String of
+ # HTML, such as removing references that the current user doesn't have
+ # permission to make (`RedactorFilter`).
+ #
+ # html - String to process
+ # context - Hash of options to customize output
+ # :pipeline - Symbol pipeline type
+ # :project - Project
+ # :user - User object
+ #
+ # Returns an HTML-safe String
+ def self.post_process(html, context)
+ context = Pipeline[context[:pipeline]].transform_context(context)
+
+ pipeline = Pipeline[:post_process]
+ if context[:xhtml]
+ pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
+ else
+ pipeline.to_html(html, context)
+ end.html_safe
+ end
+
+ private
+
+ def self.cacheless_render(text, context = {})
+ result = render_result(text, context)
+
+ output = result[:output]
+ if output.respond_to?(:to_html)
+ output.to_html
+ else
+ output.to_s
+ end
+ end
+
+ def self.full_cache_key(cache_key, pipeline_name)
+ return unless cache_key
+ ["banzai", *cache_key, pipeline_name || :full]
+ end
+ end
+end
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index 443563c2e4a..1c91204e98c 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -19,7 +19,7 @@ module Ci
end
def runner_registration_token_valid?
- params[:token] == current_application_settings.ensure_runners_registration_token
+ params[:token] == current_application_settings.runners_registration_token
end
def update_runner_last_contact
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index 330d3342dd1..b203b9d70e4 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -32,7 +32,7 @@ module Gitlab
html = ::Asciidoctor.convert(input, asciidoc_opts)
if context[:project]
- html = Gitlab::Markdown.render(html, context.merge(pipeline: :asciidoc))
+ html = Banzai.render(html, context.merge(pipeline: :asciidoc))
end
html.html_safe
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 87ac30b5ffe..459e3d6bcdb 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -2,7 +2,7 @@ module Gitlab
class Shell
class Error < StandardError; end
- class KeyAdder < Struct.new(:io)
+ KeyAdder = Struct.new(:io) do
def add_key(id, key)
key.gsub!(/[[:space:]]+/, ' ').strip!
io.puts("#{id}\t#{key}")
diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb
index 35e34d033e0..03aac1a025a 100644
--- a/lib/gitlab/bitbucket_import/project_creator.rb
+++ b/lib/gitlab/bitbucket_import/project_creator.rb
@@ -11,7 +11,8 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(
+ current_user,
name: repo["name"],
path: repo["slug"],
description: repo["description"],
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 142058aa69d..79061cd0141 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -46,11 +46,11 @@ module Gitlab
end
def added_lines
- diff_lines.select(&:added?).size
+ diff_lines.count(&:added?)
end
def removed_lines
- diff_lines.select(&:removed?).size
+ diff_lines.count(&:removed?)
end
end
end
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
index 496256700b8..403ebeec474 100644
--- a/lib/gitlab/fogbugz_import/importer.rb
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -199,7 +199,7 @@ module Gitlab
s = s.gsub(/^#/, "\\#")
s = s.gsub(/^-/, "\\-")
s = s.gsub("`", "\\~")
- s = s.gsub("\r", "")
+ s = s.delete("\r")
s = s.gsub("\n", " \n")
s
end
diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb
index 8b1b6f48ed5..e0163499e30 100644
--- a/lib/gitlab/fogbugz_import/project_creator.rb
+++ b/lib/gitlab/fogbugz_import/project_creator.rb
@@ -12,7 +12,8 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(
+ current_user,
name: repo.safe_name,
path: repo.path,
namespace: namespace,
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 0c350d7c675..f065cc5e9e9 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -20,6 +20,10 @@ module Gitlab
def blank_ref?(ref)
ref == BLANK_SHA
end
+
+ def version
+ Gitlab::VersionInfo.parse(Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --version)).first)
+ end
end
end
end
diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb
index d9452de6a50..7baaadb813c 100644
--- a/lib/gitlab/gitlab_import/project_creator.rb
+++ b/lib/gitlab/gitlab_import/project_creator.rb
@@ -11,7 +11,8 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(
+ current_user,
name: repo["name"],
path: repo["path"],
description: repo["description"],
diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb
index cc9a91c91f4..8e22aa9286d 100644
--- a/lib/gitlab/gitorious_import/project_creator.rb
+++ b/lib/gitlab/gitorious_import/project_creator.rb
@@ -10,7 +10,8 @@ module Gitlab
end
def execute
- ::Projects::CreateService.new(current_user,
+ ::Projects::CreateService.new(
+ current_user,
name: repo.name,
path: repo.path,
description: repo.description,
diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb
index 87fee28dc01..62da327931f 100644
--- a/lib/gitlab/google_code_import/importer.rb
+++ b/lib/gitlab/google_code_import/importer.rb
@@ -171,8 +171,6 @@ module Gitlab
when /\AMilestone:/
"#fee3ff"
- when *@closed_statuses.map { |s| nice_status_name(s) }
- "#cfcfcf"
when "Status: New"
"#428bca"
when "Status: Accepted"
@@ -199,6 +197,8 @@ module Gitlab
"#8e44ad"
when "Type: Other"
"#7f8c8d"
+ when *@closed_statuses.map { |s| nice_status_name(s) }
+ "#cfcfcf"
else
"#e2e2e2"
end
@@ -227,7 +227,7 @@ module Gitlab
s = s.gsub("`", "\\`")
# Carriage returns make me sad
- s = s.gsub("\r", "")
+ s = s.delete("\r")
# Markdown ignores single newlines, but we need them as <br />.
s = s.gsub("\n", " \n")
diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb
index 1cb7d16aeb3..87821c23460 100644
--- a/lib/gitlab/google_code_import/project_creator.rb
+++ b/lib/gitlab/google_code_import/project_creator.rb
@@ -11,7 +11,8 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(
+ current_user,
name: repo.name,
path: repo.name,
description: repo.summary,
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
deleted file mode 100644
index f4e2cefca51..00000000000
--- a/lib/gitlab/markdown.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require 'html/pipeline'
-
-module Gitlab
- # Custom parser for GitLab-flavored Markdown
- #
- # See the files in `lib/gitlab/markdown/` for specific processing information.
- module Markdown
- # Convert a Markdown String into an HTML-safe String of HTML
- #
- # Note that while the returned HTML will have been sanitized of dangerous
- # HTML, it may post a risk of information leakage if it's not also passed
- # through `post_process`.
- #
- # Also note that the returned String is always HTML, not XHTML. Views
- # requiring XHTML, such as Atom feeds, need to call `post_process` on the
- # result, providing the appropriate `pipeline` option.
- #
- # markdown - Markdown String
- # context - Hash of context options passed to our HTML Pipeline
- #
- # Returns an HTML-safe String
- def self.render(text, context = {})
- cache_key = context.delete(:cache_key)
- cache_key = full_cache_key(cache_key, context[:pipeline])
-
- if cache_key
- Rails.cache.fetch(cache_key) do
- cacheless_render(text, context)
- end
- else
- cacheless_render(text, context)
- end
- end
-
- def self.render_result(text, context = {})
- Pipeline[context[:pipeline]].call(text, context)
- end
-
- # Perform post-processing on an HTML String
- #
- # This method is used to perform state-dependent changes to a String of
- # HTML, such as removing references that the current user doesn't have
- # permission to make (`RedactorFilter`).
- #
- # html - String to process
- # context - Hash of options to customize output
- # :pipeline - Symbol pipeline type
- # :project - Project
- # :user - User object
- #
- # Returns an HTML-safe String
- def self.post_process(html, context)
- context = Pipeline[context[:pipeline]].transform_context(context)
-
- pipeline = Pipeline[:post_process]
- if context[:xhtml]
- pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
- else
- pipeline.to_html(html, context)
- end.html_safe
- end
-
- private
-
- def self.cacheless_render(text, context = {})
- result = render_result(text, context)
-
- output = result[:output]
- if output.respond_to?(:to_html)
- output.to_html
- else
- output.to_s
- end
- end
-
- def self.full_cache_key(cache_key, pipeline_name)
- return unless cache_key
- ["markdown", *cache_key, pipeline_name || :full]
- end
-
- # Provide autoload paths for filters to prevent a circular dependency error
- autoload :AutolinkFilter, 'gitlab/markdown/filter/autolink_filter'
- autoload :CommitRangeReferenceFilter, 'gitlab/markdown/filter/commit_range_reference_filter'
- autoload :CommitReferenceFilter, 'gitlab/markdown/filter/commit_reference_filter'
- autoload :EmojiFilter, 'gitlab/markdown/filter/emoji_filter'
- autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/filter/external_issue_reference_filter'
- autoload :ExternalLinkFilter, 'gitlab/markdown/filter/external_link_filter'
- autoload :IssueReferenceFilter, 'gitlab/markdown/filter/issue_reference_filter'
- autoload :LabelReferenceFilter, 'gitlab/markdown/filter/label_reference_filter'
- autoload :MarkdownFilter, 'gitlab/markdown/filter/markdown_filter'
- autoload :MergeRequestReferenceFilter, 'gitlab/markdown/filter/merge_request_reference_filter'
- autoload :RedactorFilter, 'gitlab/markdown/filter/redactor_filter'
- autoload :ReferenceGathererFilter, 'gitlab/markdown/filter/reference_gatherer_filter'
- autoload :RelativeLinkFilter, 'gitlab/markdown/filter/relative_link_filter'
- autoload :SanitizationFilter, 'gitlab/markdown/filter/sanitization_filter'
- autoload :SnippetReferenceFilter, 'gitlab/markdown/filter/snippet_reference_filter'
- autoload :SyntaxHighlightFilter, 'gitlab/markdown/filter/syntax_highlight_filter'
- autoload :TableOfContentsFilter, 'gitlab/markdown/filter/table_of_contents_filter'
- autoload :TaskListFilter, 'gitlab/markdown/filter/task_list_filter'
- autoload :UserReferenceFilter, 'gitlab/markdown/filter/user_reference_filter'
- autoload :UploadLinkFilter, 'gitlab/markdown/filter/upload_link_filter'
-
- autoload :AsciidocPipeline, 'gitlab/markdown/pipeline/asciidoc_pipeline'
- autoload :AtomPipeline, 'gitlab/markdown/pipeline/atom_pipeline'
- autoload :DescriptionPipeline, 'gitlab/markdown/pipeline/description_pipeline'
- autoload :EmailPipeline, 'gitlab/markdown/pipeline/email_pipeline'
- autoload :FullPipeline, 'gitlab/markdown/pipeline/full_pipeline'
- autoload :GfmPipeline, 'gitlab/markdown/pipeline/gfm_pipeline'
- autoload :NotePipeline, 'gitlab/markdown/pipeline/note_pipeline'
- autoload :PlainMarkdownPipeline, 'gitlab/markdown/pipeline/plain_markdown_pipeline'
- autoload :PostProcessPipeline, 'gitlab/markdown/pipeline/post_process_pipeline'
- autoload :ReferenceExtractionPipeline, 'gitlab/markdown/pipeline/reference_extraction_pipeline'
- autoload :SingleLinePipeline, 'gitlab/markdown/pipeline/single_line_pipeline'
- end
-end
diff --git a/lib/gitlab/markdown/cross_project_reference.rb b/lib/gitlab/markdown/cross_project_reference.rb
deleted file mode 100644
index 6ab04a584b0..00000000000
--- a/lib/gitlab/markdown/cross_project_reference.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # Common methods for ReferenceFilters that support an optional cross-project
- # reference.
- module CrossProjectReference
- # Given a cross-project reference string, get the Project record
- #
- # Defaults to value of `context[:project]` if:
- # * No reference is given OR
- # * Reference given doesn't exist
- #
- # ref - String reference.
- #
- # Returns a Project, or nil if the reference can't be found
- def project_from_ref(ref)
- return context[:project] unless ref
-
- Project.find_with_namespace(ref)
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline.rb b/lib/gitlab/markdown/pipeline.rb
index d683756f95a..8f3f43c0e91 100644
--- a/lib/gitlab/markdown/pipeline.rb
+++ b/lib/gitlab/markdown/pipeline.rb
@@ -1,11 +1,11 @@
-require 'gitlab/markdown'
+require 'banzai'
module Gitlab
module Markdown
class Pipeline
def self.[](name)
name ||= :full
- Markdown.const_get("#{name.to_s.camelize}Pipeline")
+ const_get("#{name.to_s.camelize}Pipeline")
end
def self.filters
diff --git a/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb b/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb
deleted file mode 100644
index 6829b4acb95..00000000000
--- a/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class AsciidocPipeline < Pipeline
- def self.filters
- [
- Gitlab::Markdown::RelativeLinkFilter
- ]
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/atom_pipeline.rb b/lib/gitlab/markdown/pipeline/atom_pipeline.rb
deleted file mode 100644
index e151f8f5e5a..00000000000
--- a/lib/gitlab/markdown/pipeline/atom_pipeline.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class AtomPipeline < FullPipeline
- def self.transform_context(context)
- super(context).merge(
- only_path: false,
- xhtml: true
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/gfm_pipeline.rb b/lib/gitlab/markdown/pipeline/gfm_pipeline.rb
deleted file mode 100644
index ca90bd75d77..00000000000
--- a/lib/gitlab/markdown/pipeline/gfm_pipeline.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class GfmPipeline < Pipeline
- def self.filters
- @filters ||= [
- Gitlab::Markdown::SyntaxHighlightFilter,
- Gitlab::Markdown::SanitizationFilter,
-
- Gitlab::Markdown::UploadLinkFilter,
- Gitlab::Markdown::EmojiFilter,
- Gitlab::Markdown::TableOfContentsFilter,
- Gitlab::Markdown::AutolinkFilter,
- Gitlab::Markdown::ExternalLinkFilter,
-
- Gitlab::Markdown::UserReferenceFilter,
- Gitlab::Markdown::IssueReferenceFilter,
- Gitlab::Markdown::ExternalIssueReferenceFilter,
- Gitlab::Markdown::MergeRequestReferenceFilter,
- Gitlab::Markdown::SnippetReferenceFilter,
- Gitlab::Markdown::CommitRangeReferenceFilter,
- Gitlab::Markdown::CommitReferenceFilter,
- Gitlab::Markdown::LabelReferenceFilter,
-
- Gitlab::Markdown::TaskListFilter
- ]
- end
-
- def self.transform_context(context)
- context.merge(
- only_path: true,
-
- # EmojiFilter
- asset_host: Gitlab::Application.config.asset_host,
- asset_root: Gitlab.config.gitlab.base_url
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb b/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb
deleted file mode 100644
index 0abb93f8a03..00000000000
--- a/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class PlainMarkdownPipeline < Pipeline
- def self.filters
- [
- Gitlab::Markdown::MarkdownFilter
- ]
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/post_process_pipeline.rb b/lib/gitlab/markdown/pipeline/post_process_pipeline.rb
deleted file mode 100644
index 60cc32f490e..00000000000
--- a/lib/gitlab/markdown/pipeline/post_process_pipeline.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class PostProcessPipeline < Pipeline
- def self.filters
- [
- Gitlab::Markdown::RelativeLinkFilter,
- Gitlab::Markdown::RedactorFilter
- ]
- end
-
- def self.transform_context(context)
- context.merge(
- post_process: true
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb b/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb
deleted file mode 100644
index a89ab462bac..00000000000
--- a/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class ReferenceExtractionPipeline < Pipeline
- def self.filters
- [
- Gitlab::Markdown::ReferenceGathererFilter
- ]
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/pipeline/single_line_pipeline.rb b/lib/gitlab/markdown/pipeline/single_line_pipeline.rb
deleted file mode 100644
index 2f24927b879..00000000000
--- a/lib/gitlab/markdown/pipeline/single_line_pipeline.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- class SingleLinePipeline < GfmPipeline
-
- end
- end
-end
diff --git a/lib/gitlab/o_auth/session.rb b/lib/gitlab/o_auth/session.rb
new file mode 100644
index 00000000000..f33bfd0bd0e
--- /dev/null
+++ b/lib/gitlab/o_auth/session.rb
@@ -0,0 +1,17 @@
+module Gitlab
+ module OAuth
+ module Session
+ def self.create(provider, ticket)
+ Rails.cache.write("gitlab:#{provider}:#{ticket}", ticket, expires_in: Gitlab.config.omniauth.cas3.session_duration)
+ end
+
+ def self.destroy(provider, ticket)
+ Rails.cache.delete("gitlab:#{provider}:#{ticket}")
+ end
+
+ def self.valid?(provider, ticket)
+ Rails.cache.read("gitlab:#{provider}:#{ticket}").present?
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index e83167fa7d7..0a70d21b1ce 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -1,62 +1,37 @@
-require 'gitlab/markdown'
+require 'banzai'
module Gitlab
# Extract possible GFM references from an arbitrary String for further processing.
- class ReferenceExtractor
- attr_accessor :project, :current_user, :load_lazy_references
+ class ReferenceExtractor < Banzai::ReferenceExtractor
+ attr_accessor :project, :current_user
- def initialize(project, current_user = nil, load_lazy_references: true)
+ def initialize(project, current_user = nil)
@project = project
@current_user = current_user
- @load_lazy_references = load_lazy_references
- @texts = []
@references = {}
+
+ super()
end
- def analyze(text, options = {})
- @texts << Gitlab::Markdown.render(text, options.merge(project: project))
+ def analyze(text, context = {})
+ super(text, context.merge(project: project))
end
- %i(user label issue merge_request snippet commit commit_range).each do |type|
+ %i(user label merge_request snippet commit commit_range).each do |type|
define_method("#{type}s") do
- @references[type] ||= pipeline_result(type)
+ @references[type] ||= references(type, project: project, current_user: current_user)
end
end
- private
-
- # Instantiate and call HTML::Pipeline with a single reference filter type,
- # returning the result
- #
- # filter_type - Symbol reference type (e.g., :commit, :issue, etc.)
- #
- # Returns the results Array for the requested filter type
- def pipeline_result(filter_type)
- filter = Gitlab::Markdown::ReferenceFilter[filter_type]
-
- context = {
- pipeline: :reference_extraction,
-
- project: project,
- current_user: current_user,
+ def issues
+ options = { project: project, current_user: current_user }
- # ReferenceGathererFilter
- load_lazy_references: false,
- reference_filter: filter
- }
-
- values = @texts.flat_map do |html|
- text_context = context.dup
- result = Gitlab::Markdown.render_result(html, text_context)
- result[:references][filter_type]
- end.uniq
-
- if @load_lazy_references
- values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq
+ if project && project.jira_tracker?
+ @references[:external_issue] ||= references(:external_issue, options)
+ else
+ @references[:issue] ||= references(:issue, options)
end
-
- values
end
end
end
diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb
index 6762ca47c32..8c309efc7b8 100644
--- a/lib/rouge/formatters/html_gitlab.rb
+++ b/lib/rouge/formatters/html_gitlab.rb
@@ -39,7 +39,7 @@ module Rouge
lineanchorsid: 'L',
anchorlinenos: false,
inline_theme: nil
- )
+ )
@nowrap = nowrap
@cssclass = cssclass
@linenos = linenos
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index 43fda6fa92e..c5f07c8b508 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -33,12 +33,13 @@ app_user="git"
app_root="/home/$app_user/gitlab"
pid_path="$app_root/tmp/pids"
socket_path="$app_root/tmp/sockets"
+rails_socket="$socket_path/gitlab.socket"
web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid"
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
-gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
+gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $rails_socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
shell_path="/bin/bash"
@@ -91,7 +92,7 @@ check_pids(){
## Called when we have started the two processes and are waiting for their pid files.
wait_for_pids(){
- # We are sleeping a bit here mostly because sidekiq is slow at writing it's pid
+ # We are sleeping a bit here mostly because sidekiq is slow at writing its pid
i=0;
while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_workhorse_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
sleep 0.1;
@@ -107,7 +108,7 @@ wait_for_pids(){
}
# We use the pids in so many parts of the script it makes sense to always check them.
-# Only after start() is run should the pids change. Sidekiq sets it's own pid.
+# Only after start() is run should the pids change. Sidekiq sets its own pid.
check_pids
@@ -289,7 +290,7 @@ stop_gitlab() {
sleep 1
# Cleaning up unused pids
rm "$web_server_pid_path" 2>/dev/null
- # rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid.
+ # rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up its own pid.
rm -f "$gitlab_workhorse_pid_path"
if [ "$mail_room_enabled" = true ]; then
rm "$mail_room_pid_path" 2>/dev/null
@@ -298,7 +299,7 @@ stop_gitlab() {
print_status
}
-## Prints the status of GitLab and it's components.
+## Prints the status of GitLab and its components.
print_status() {
check_status
if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
@@ -332,7 +333,7 @@ print_status() {
fi
}
-## Tells unicorn to reload it's config and Sidekiq to restart
+## Tells unicorn to reload its config and Sidekiq to restart
reload_gitlab(){
exit_if_not_running
if [ "$wpid" = "0" ];then
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index 79ae8e0ae55..1937ca582b0 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -9,11 +9,11 @@ RAILS_ENV="production"
# The default is "git".
app_user="git"
-# app_root defines the folder in which gitlab and it's components are installed.
+# app_root defines the folder in which gitlab and its components are installed.
# The default is "/home/$app_user/gitlab"
app_root="/home/$app_user/gitlab"
-# pid_path defines a folder in which the gitlab and it's components place their pids.
+# pid_path defines a folder in which the gitlab and its components place their pids.
# This variable is also used below to define the relevant pids for the gitlab components.
# The default is "$app_root/tmp/pids"
pid_path="$app_root/tmp/pids"
@@ -36,7 +36,7 @@ gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
# '-listenNetwork tcp -listenAddr localhost:8181'.
# The -authBackend setting tells gitlab-workhorse where it can reach
# Unicorn.
-gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
+gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $socket_path/gitlab.socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 2a79fbdcf93..fc5475c4eef 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -10,34 +10,12 @@
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
-##################################
-## CHUNKED TRANSFER ##
-##################################
-##
-## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
-## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
-## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
-## around this by tweaking this configuration file and either:
-## - installing an old version of Nginx with the chunkin module [2] compiled in, or
-## - using a newer version of Nginx.
-##
-## At the time of writing we do not know if either of these theoretical solutions works.
-## As a workaround users can use Git over SSH to push large files.
-##
-## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
-## [1] https://github.com/agentzh/chunkin-nginx-module#status
-## [2] https://github.com/agentzh/chunkin-nginx-module
-##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
-upstream gitlab {
- server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
-}
-
upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
@@ -54,10 +32,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
- ## Increase this if you want to upload large attachments
- ## Or if you want to accept large git objects over http
- client_max_body_size 20m;
-
## See app/controllers/application_controller.rb for headers set
## Individual nginx logs for this GitLab vhost
@@ -65,103 +39,8 @@ server {
error_log /var/log/nginx/gitlab_error.log;
location / {
- ## Serve static files from defined root folder.
- ## @gitlab is a named location for the upstream fallback, see below.
- try_files $uri /index.html $uri.html @gitlab;
- }
-
- ## We route uploads through GitLab to prevent XSS and enforce access control.
- location /uploads/ {
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
- # gzip off;
-
- ## https://github.com/gitlabhq/gitlabhq/issues/694
- ## Some requests take more than 30 seconds.
- proxy_read_timeout 300;
- proxy_connect_timeout 300;
- proxy_redirect off;
-
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Frame-Options SAMEORIGIN;
-
- proxy_pass http://gitlab;
- }
-
- ## If a file, which is not found in the root folder is requested,
- ## then the proxy passes the request to the upsteam (gitlab unicorn).
- location @gitlab {
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
- # gzip off;
-
- ## https://github.com/gitlabhq/gitlabhq/issues/694
- ## Some requests take more than 30 seconds.
- proxy_read_timeout 300;
- proxy_connect_timeout 300;
- proxy_redirect off;
-
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Frame-Options SAMEORIGIN;
-
- proxy_pass http://gitlab;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/api/v3/projects/.*/repository/archive {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- # Build artifacts should be submitted to this location
- location ~ ^/[\w\.-]+/[\w\.-]+/builds/download {
client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- # Build artifacts should be submitted to this location
- location ~ /ci/api/v1/builds/[0-9]+/artifacts {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location @gitlab-workhorse {
- client_max_body_size 0;
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
- # gzip off;
+ gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
@@ -169,14 +48,7 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
- # Do not buffer Git HTTP responses
- proxy_buffering off;
-
- # The following settings only work with NGINX 1.7.11 or newer
- #
- # # Pass chunked request bodies to gitlab-workhorse as-is
- # proxy_request_buffering off;
- # proxy_http_version 1.1;
+ proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
@@ -185,18 +57,4 @@ server {
proxy_pass http://gitlab-workhorse;
}
-
- ## Enable gzip compression as per rails guide:
- ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- ## WARNING: If you are using relative urls remove the block below
- ## See config/application.rb under "Relative url support" for the list of
- ## other files that need to be changed for relative url support
- location ~ ^/(assets)/ {
- root /home/git/gitlab/public;
- gzip_static on; # to serve pre-gzipped version
- expires max;
- add_header Cache-Control public;
- }
-
- error_page 502 /502.html;
}
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 79fe1474821..1e5f85413ec 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -14,34 +14,12 @@
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
-##################################
-## CHUNKED TRANSFER ##
-##################################
-##
-## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
-## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
-## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
-## around this by tweaking this configuration file and either:
-## - installing an old version of Nginx with the chunkin module [2] compiled in, or
-## - using a newer version of Nginx.
-##
-## At the time of writing we do not know if either of these theoretical solutions works.
-## As a workaround users can use Git over SSH to push large files.
-##
-## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
-## [1] https://github.com/agentzh/chunkin-nginx-module#status
-## [2] https://github.com/agentzh/chunkin-nginx-module
-##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
-upstream gitlab {
- server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
-}
-
upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
@@ -61,7 +39,6 @@ server {
error_log /var/log/nginx/gitlab_error.log;
}
-
## HTTPS host
server {
listen 0.0.0.0:443 ssl;
@@ -70,10 +47,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
- ## Increase this if you want to upload large attachments
- ## Or if you want to accept large git objects over http
- client_max_body_size 20m;
-
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on;
@@ -110,104 +83,7 @@ server {
error_log /var/log/nginx/gitlab_error.log;
location / {
- ## Serve static files from defined root folder.
- ## @gitlab is a named location for the upstream fallback, see below.
- try_files $uri /index.html $uri.html @gitlab;
- }
-
- ## We route uploads through GitLab to prevent XSS and enforce access control.
- location /uploads/ {
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
- gzip off;
-
- ## https://github.com/gitlabhq/gitlabhq/issues/694
- ## Some requests take more than 30 seconds.
- proxy_read_timeout 300;
- proxy_connect_timeout 300;
- proxy_redirect off;
-
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-Ssl on;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Frame-Options SAMEORIGIN;
-
- proxy_pass http://gitlab;
- }
-
- ## If a file, which is not found in the root folder is requested,
- ## then the proxy passes the request to the upsteam (gitlab unicorn).
- location @gitlab {
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
- gzip off;
-
- ## https://github.com/gitlabhq/gitlabhq/issues/694
- ## Some requests take more than 30 seconds.
- proxy_read_timeout 300;
- proxy_connect_timeout 300;
- proxy_redirect off;
-
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-Ssl on;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Frame-Options SAMEORIGIN;
-
- proxy_pass http://gitlab;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location ~ ^/api/v3/projects/.*/repository/archive {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- # Build artifacts should be submitted to this location
- location ~ ^/[\w\.-]+/[\w\.-]+/builds/download {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- # Build artifacts should be submitted to this location
- location ~ /ci/api/v1/builds/[0-9]+/artifacts {
- client_max_body_size 0;
- # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
- error_page 418 = @gitlab-workhorse;
- return 418;
- }
-
- location @gitlab-workhorse {
- client_max_body_size 0;
- ## If you use HTTPS make sure you disable gzip compression
- ## to be safe against BREACH attack.
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
@@ -216,14 +92,7 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
- # Do not buffer Git HTTP responses
- proxy_buffering off;
-
- # The following settings only work with NGINX 1.7.11 or newer
- #
- # # Pass chunked request bodies to gitlab-workhorse as-is
- # proxy_request_buffering off;
- # proxy_http_version 1.1;
+ proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
@@ -232,18 +101,4 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse;
}
-
- ## Enable gzip compression as per rails guide:
- ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- ## WARNING: If you are using relative urls remove the block below
- ## See config/application.rb under "Relative url support" for the list of
- ## other files that need to be changed for relative url support
- location ~ ^/(assets)/ {
- root /home/git/gitlab/public;
- gzip_static on; # to serve pre-gzipped version
- expires max;
- add_header Cache-Control public;
- }
-
- error_page 502 /502.html;
}
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index b5af3d88b4c..0469c5a61c3 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -822,10 +822,27 @@ namespace :gitlab do
namespace_dirs.each do |namespace_dir|
repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
- repo_dirs.each do |dir|
- puts "\nChecking repo at #{dir}"
- system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir)
- end
+ repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
+ end
+ end
+ end
+
+ namespace :user do
+ desc "GitLab | Check the integrity of a specific user's repositories"
+ task :check_repos, [:username] => :environment do |t, args|
+ username = args[:username] || prompt("Check repository integrity for which username? ".blue)
+ user = User.find_by(username: username)
+ if user
+ repo_dirs = user.authorized_projects.map do |p|
+ File.join(
+ Gitlab.config.gitlab_shell.repos_path,
+ "#{p.path_with_namespace}.git"
+ )
+ end
+
+ repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
+ else
+ puts "\nUser '#{username}' not found".red
end
end
end
@@ -952,4 +969,35 @@ namespace :gitlab do
false
end
end
+
+ def check_repo_integrity(repo_dir)
+ puts "\nChecking repo at #{repo_dir.yellow}"
+
+ git_fsck(repo_dir)
+ check_config_lock(repo_dir)
+ check_ref_locks(repo_dir)
+ end
+
+ def git_fsck(repo_dir)
+ puts "Running `git fsck`".yellow
+ system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir)
+ end
+
+ def check_config_lock(repo_dir)
+ config_exists = File.exist?(File.join(repo_dir,'config.lock'))
+ config_output = config_exists ? 'yes'.red : 'no'.green
+ puts "'config.lock' file exists?".yellow + " ... #{config_output}"
+ end
+
+ def check_ref_locks(repo_dir)
+ lock_files = Dir.glob(File.join(repo_dir,'refs/heads/*.lock'))
+ if lock_files.present?
+ puts "Ref lock files exist:".red
+ lock_files.each do |lock_file|
+ puts " #{lock_file}"
+ end
+ else
+ puts "No ref lock files exist".green
+ end
+ end
end
diff --git a/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
index 34cd9f7e4eb..3855763b200 100644
--- a/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
+++ b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::ReferenceFilter, benchmark: true do
+describe Banzai::Filter::ReferenceFilter, benchmark: true do
let(:input) do
html = <<-EOF
<p>Hello @alice and @bob, how are you doing today?</p>
diff --git a/spec/factories.rb b/spec/factories.rb
index 4bf93adabe2..d6b4efa9a03 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -43,7 +43,8 @@ FactoryGirl.define do
end
after(:create) do |user, evaluator|
- user.identities << create(:identity,
+ user.identities << create(
+ :identity,
provider: evaluator.provider,
extern_uid: evaluator.extern_uid
)
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 66a2cc0c157..26d03944b8a 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -63,7 +63,7 @@ describe "Admin Runners" do
end
describe 'runners registration token' do
- let!(:token) { current_application_settings.ensure_runners_registration_token }
+ let!(:token) { current_application_settings.runners_registration_token }
before { visit admin_runners_path }
it 'has a registration token' do
diff --git a/spec/features/ci_lint_spec.rb b/spec/features/ci_lint_spec.rb
new file mode 100644
index 00000000000..e6e73e5e67c
--- /dev/null
+++ b/spec/features/ci_lint_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'CI Lint' do
+ before do
+ login_as :user
+ end
+
+ describe 'YAML parsing' do
+ before do
+ visit ci_lint_path
+ fill_in 'content', with: yaml_content
+ click_on 'Validate'
+ end
+
+ context 'YAML is correct' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ end
+
+ it 'Yaml parsing' do
+ within "table" do
+ expect(page).to have_content('Job - rspec')
+ expect(page).to have_content('Job - spinach')
+ expect(page).to have_content('Deploy Job - staging')
+ expect(page).to have_content('Deploy Job - production')
+ end
+ end
+ end
+
+ context 'YAML is incorrect' do
+ let(:yaml_content) { '' }
+
+ it 'displays information about an error' do
+ expect(page).to have_content('Status: syntax is incorrect')
+ expect(page).to have_content('Error: Please provide content of .gitlab-ci.yml')
+ end
+ end
+ end
+end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index ecc85376ffc..fe7f07f5b75 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -19,30 +19,13 @@ describe 'Commits' do
let!(:build) { FactoryGirl.create :ci_build, commit: commit }
describe 'Project commits' do
- context 'builds enabled' do
- context '.gitlab-ci.yml found' do
- before do
- visit namespace_project_commits_path(project.namespace, project, :master)
- end
-
- it 'should show build status' do
- page.within("//li[@id='commit-#{commit.short_sha}']") do
- expect(page).to have_css(".ci-status-link")
- end
- end
- end
+ before do
+ visit namespace_project_commits_path(project.namespace, project, :master)
+ end
- context 'no .gitlab-ci.yml found' do
- before do
- stub_ci_commit_yaml_file(nil)
- visit namespace_project_commits_path(project.namespace, project, :master)
- end
-
- it 'should not show build status' do
- page.within("//li[@id='commit-#{commit.short_sha}']") do
- expect(page).to have_no_css(".ci-status-link")
- end
- end
+ it 'should show build status' do
+ page.within("//li[@id='commit-#{commit.short_sha}']") do
+ expect(page).to have_css(".ci-status-link")
end
end
end
diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb
index f600f8684ac..38c8d343ce3 100644
--- a/spec/features/issues/filter_by_milestone_spec.rb
+++ b/spec/features/issues/filter_by_milestone_spec.rb
@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(Milestone::None.title)
- expect(page).to have_css('.issue-title', count: 1)
+ expect(page).to have_css('.title', count: 1)
end
scenario 'filters by a specific Milestone', js: true do
@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(milestone.title)
- expect(page).to have_css('.issue-title', count: 1)
+ expect(page).to have_css('.title', count: 1)
end
def visit_issues(project)
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
new file mode 100644
index 00000000000..e4efdbe2421
--- /dev/null
+++ b/spec/features/issues/note_polling_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+feature 'Issue notes polling' do
+ let!(:project) { create(:project, :public) }
+ let!(:issue) { create(:issue, project: project) }
+
+ background do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ scenario 'Another user adds a comment to an issue', js: true do
+ note = create(:note_on_issue, noteable: issue, note: 'Looks good!')
+ page.execute_script('notes.refresh();')
+ expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
+ end
+end
diff --git a/spec/features/lint_spec.rb b/spec/features/lint_spec.rb
deleted file mode 100644
index 5d8f56e2cfb..00000000000
--- a/spec/features/lint_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'spec_helper'
-
-describe "Lint" do
- before do
- login_as :user
- end
-
- it "Yaml parsing", js: true do
- content = File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- visit ci_lint_path
- fill_in "content", with: content
- click_on "Validate"
- within "table" do
- expect(page).to have_content("Job - rspec")
- expect(page).to have_content("Job - spinach")
- expect(page).to have_content("Deploy Job - staging")
- expect(page).to have_content("Deploy Job - production")
- end
- end
-
- it "Yaml parsing with error", js: true do
- visit ci_lint_path
- fill_in "content", with: ""
- click_on "Validate"
- expect(page).to have_content("Status: syntax is incorrect")
- expect(page).to have_content("Error: Please provide content of .gitlab-ci.yml")
- end
-end
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
index 28a46a0725d..7aa7eb965e9 100644
--- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
@@ -21,12 +21,12 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
end
it 'displays the Merge When Build Succeeds button' do
- expect(page).to have_link "Merge When Build Succeeds"
+ expect(page).to have_button "Merge When Build Succeeds"
end
context "Merge When Build succeeds enabled" do
before do
- click_link "Merge When Build Succeeds"
+ click_button "Merge When Build Succeeds"
end
it 'activates Merge When Build Succeeds feature' do
@@ -58,7 +58,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
it 'cancels the automatic merge' do
click_link "Cancel Automatic Merge"
- expect(page).to have_link "Merge When Build Succeeds"
+ expect(page).to have_button "Merge When Build Succeeds"
visit_merge_request(merge_request) # Needed to refresh the page
expect(page).to have_content "Canceled the automatic merge"
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 09fcff2444a..74b148f5d17 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -70,6 +70,20 @@ feature 'Project', feature: true do
end
end
+ describe 'leave project link' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, namespace: user.namespace) }
+
+ before do
+ login_with(user)
+ project.team.add_user(user, Gitlab::Access::MASTER)
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ it { expect(page).to have_content('You have Master access to this project.') }
+ it { expect(page).to have_link('Leave this project') }
+ end
+
def remove_with_confirm(button_text, confirm_with)
click_button button_text
fill_in 'confirm_name_input', with: confirm_with
diff --git a/spec/features/security/group_access_spec.rb b/spec/features/security/group_access_spec.rb
index 4b78e3a61f0..65f8073c693 100644
--- a/spec/features/security/group_access_spec.rb
+++ b/spec/features/security/group_access_spec.rb
@@ -16,11 +16,11 @@ describe 'Group access', feature: true do
end
end
- def group_member(access_level, group = group)
+ def group_member(access_level, grp = group())
level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
create(:user).tap do |user|
- group.add_user(user, level)
+ grp.add_user(user, level)
end
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index fca3c77fc64..b7368cca29d 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -47,7 +47,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_issue(project, issue)
- container = '.issue-details .description.js-task-list-container'
+ container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
@@ -123,7 +123,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_merge_request(project, merge)
- container = '.merge-request-details .description.js-task-list-container'
+ container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 5568f06639c..68527c3a4f8 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -263,11 +263,12 @@ describe ApplicationHelper do
end
it 'includes a default js-timeago class' do
- expect(element.attr('class')).to eq 'time_ago js-timeago'
+ expect(element.attr('class')).to eq 'time_ago js-timeago js-timeago-pending'
end
it 'accepts a custom html_class' do
- expect(element(html_class: 'custom_class').attr('class')).to eq 'custom_class js-timeago'
+ expect(element(html_class: 'custom_class').attr('class')).
+ to eq 'custom_class js-timeago js-timeago-pending'
end
it 'accepts a custom tooltip placement' do
@@ -278,7 +279,7 @@ describe ApplicationHelper do
el = element.next_element
expect(el.name).to eq 'script'
- expect(el.text).to include "$('.js-timeago').last().timeago()"
+ expect(el.text).to include "$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
end
it 'allows the script tag to be excluded' do
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index 7fc53eb1472..4f8d9c67262 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -6,13 +6,8 @@ describe CiStatusHelper do
let(:success_commit) { double("Ci::Commit", status: 'success') }
let(:failed_commit) { double("Ci::Commit", status: 'failed') }
- describe 'ci_status_color' do
- it { expect(ci_status_icon(success_commit)).to include('fa-check') }
- it { expect(ci_status_icon(failed_commit)).to include('fa-close') }
- end
-
- describe 'ci_status_color' do
- it { expect(ci_status_color(success_commit)).to eq('green') }
- it { expect(ci_status_color(failed_commit)).to eq('red') }
+ describe 'ci_status_icon' do
+ it { expect(helper.ci_status_icon(success_commit)).to include('fa-check') }
+ it { expect(helper.ci_status_icon(failed_commit)).to include('fa-close') }
end
end
diff --git a/spec/helpers/groups_helper.rb b/spec/helpers/groups_helper.rb
index 5d174460681..4ea90a80a92 100644
--- a/spec/helpers/groups_helper.rb
+++ b/spec/helpers/groups_helper.rb
@@ -9,7 +9,7 @@ describe GroupsHelper do
group.avatar = File.open(avatar_file_path)
group.save!
expect(group_icon(group.path).to_s).
- to match("/uploads/group/avatar/#{ group.id }/banana_sample.gif")
+ to match("/uploads/group/avatar/#{group.id}/banana_sample.gif")
end
it 'should give default avatar_icon when no avatar is present' do
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 0ef1efb8bce..600e1c4e9ec 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -1,24 +1,57 @@
require 'spec_helper'
describe MergeRequestsHelper do
- describe "#issues_sentence" do
+ describe 'ci_build_details_path' do
+ let(:project) { create :project }
+ let(:merge_request) { MergeRequest.new }
+ let(:ci_service) { CiService.new }
+ let(:last_commit) { Ci::Commit.new({}) }
+
+ before do
+ allow(merge_request).to receive(:source_project).and_return(project)
+ allow(merge_request).to receive(:last_commit).and_return(last_commit)
+ allow(project).to receive(:ci_service).and_return(ci_service)
+ allow(last_commit).to receive(:sha).and_return('12d65c')
+ end
+
+ it 'does not include api credentials in a link' do
+ allow(ci_service).
+ to receive(:build_page).and_return("http://secretuser:secretpass@jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c")
+ expect(helper.ci_build_details_path(merge_request)).to_not match("secret")
+ end
+ end
+
+ describe '#issues_sentence' do
subject { issues_sentence(issues) }
let(:issues) do
[build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)]
end
it { is_expected.to eq('#1, #2, and #3') }
+
+ context 'for JIRA issues' do
+ let(:project) { create(:project) }
+ let(:issues) do
+ [
+ JiraIssue.new('JIRA-123', project),
+ JiraIssue.new('JIRA-456', project),
+ JiraIssue.new('FOOBAR-7890', project)
+ ]
+ end
+
+ it { is_expected.to eq('FOOBAR-7890, JIRA-123, and JIRA-456') }
+ end
end
- describe "#format_mr_branch_names" do
- describe "within the same project" do
+ describe '#format_mr_branch_names' do
+ describe 'within the same project' do
let(:merge_request) { create(:merge_request) }
subject { format_mr_branch_names(merge_request) }
it { is_expected.to eq([merge_request.source_branch, merge_request.target_branch]) }
end
- describe "within different projects" do
+ describe 'within different projects' do
let(:project) { create(:project) }
let(:fork_project) { create(:project, forked_from_project: project) }
let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) }
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index f2efb528aeb..53207767581 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -53,6 +53,16 @@ describe ProjectsHelper do
end
end
+ describe 'user_max_access_in_project' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ before do
+ project.team.add_user(user, Gitlab::Access::MASTER)
+ end
+
+ it { expect(helper.user_max_access_in_project(user.id, project)).to eq('Master') }
+ end
+
describe "readme_cache_key" do
let(:project) { create(:project) }
diff --git a/spec/javascripts/fixtures/issues_show.html.haml b/spec/javascripts/fixtures/issues_show.html.haml
index 7e8b2a64351..8447dfdda32 100644
--- a/spec/javascripts/fixtures/issues_show.html.haml
+++ b/spec/javascripts/fixtures/issues_show.html.haml
@@ -1,6 +1,6 @@
%a.btn-close
-.issue-details
+.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml
index f0c622935f8..8447dfdda32 100644
--- a/spec/javascripts/fixtures/merge_requests_show.html.haml
+++ b/spec/javascripts/fixtures/merge_requests_show.html.haml
@@ -1,6 +1,6 @@
%a.btn-close
-.merge-request-details
+.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
diff --git a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index f594fe4ccf6..81b9a513ce3 100644
--- a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::CrossProjectReference, lib: true do
+describe Banzai::CrossProjectReference, lib: true do
include described_class
describe '#project_from_ref' do
diff --git a/spec/lib/gitlab/markdown/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index a0844aee559..84c2ddf444e 100644
--- a/spec/lib/gitlab/markdown/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::AutolinkFilter, lib: true do
+describe Banzai::Filter::AutolinkFilter, lib: true do
include FilterSpecHelper
let(:link) { 'http://about.gitlab.com/' }
diff --git a/spec/lib/gitlab/markdown/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index 570c9767628..c2a8ad36c30 100644
--- a/spec/lib/gitlab/markdown/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::CommitRangeReferenceFilter, lib: true do
+describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:project, :public) }
diff --git a/spec/lib/gitlab/markdown/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 76e7957bbb9..473534ba68a 100644
--- a/spec/lib/gitlab/markdown/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::CommitReferenceFilter, lib: true do
+describe Banzai::Filter::CommitReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:project, :public) }
diff --git a/spec/lib/gitlab/markdown/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb
index ea9b81862cf..cf314058158 100644
--- a/spec/lib/gitlab/markdown/filter/emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/emoji_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::EmojiFilter, lib: true do
+describe Banzai::Filter::EmojiFilter, lib: true do
include FilterSpecHelper
before do
diff --git a/spec/lib/gitlab/markdown/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index d8420102648..953466679e4 100644
--- a/spec/lib/gitlab/markdown/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::ExternalIssueReferenceFilter, lib: true do
+describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
include FilterSpecHelper
def helper
diff --git a/spec/lib/gitlab/markdown/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index e559f5741cc..e3a8e15330e 100644
--- a/spec/lib/gitlab/markdown/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::ExternalLinkFilter, lib: true do
+describe Banzai::Filter::ExternalLinkFilter, lib: true do
include FilterSpecHelper
it 'ignores elements without an href attribute' do
diff --git a/spec/lib/gitlab/markdown/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 1aa5d44568e..5a0d3d577a8 100644
--- a/spec/lib/gitlab/markdown/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::IssueReferenceFilter, lib: true do
+describe Banzai::Filter::IssueReferenceFilter, lib: true do
include FilterSpecHelper
def helper
diff --git a/spec/lib/gitlab/markdown/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 4fcbb329fe4..b46ccc47605 100644
--- a/spec/lib/gitlab/markdown/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'html/pipeline'
-describe Gitlab::Markdown::LabelReferenceFilter, lib: true do
+describe Banzai::Filter::LabelReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/gitlab/markdown/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index 589550e15c4..352710df307 100644
--- a/spec/lib/gitlab/markdown/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::MergeRequestReferenceFilter, lib: true do
+describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:project, :public) }
diff --git a/spec/lib/gitlab/markdown/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index 9e6ee9f0d61..e9bb388e361 100644
--- a/spec/lib/gitlab/markdown/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::RedactorFilter, lib: true do
+describe Banzai::Filter::RedactorFilter, lib: true do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/gitlab/markdown/filter/reference_gatherer_filter_spec.rb b/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
index abfb5ad5e49..c8b1dfdf944 100644
--- a/spec/lib/gitlab/markdown/filter/reference_gatherer_filter_spec.rb
+++ b/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::ReferenceGathererFilter, lib: true do
+describe Banzai::Filter::ReferenceGathererFilter, lib: true do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/gitlab/markdown/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index e0f53e2a533..0b3e5ecbc9f 100644
--- a/spec/lib/gitlab/markdown/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Markdown::RelativeLinkFilter, lib: true do
+describe Banzai::Filter::RelativeLinkFilter, lib: true do
def filter(doc, contexts = {})
contexts.reverse_merge!({
commit: project.commit,
diff --git a/spec/lib/gitlab/markdown/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index a5e5ee0e08a..760d60a4190 100644
--- a/spec/lib/gitlab/markdown/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::SanitizationFilter, lib: true do
+describe Banzai::Filter::SanitizationFilter, lib: true do
include FilterSpecHelper
describe 'default whitelist' do
diff --git a/spec/lib/gitlab/markdown/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index 51526b58597..26466fbb180 100644
--- a/spec/lib/gitlab/markdown/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::SnippetReferenceFilter, lib: true do
+describe Banzai::Filter::SnippetReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/gitlab/markdown/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 8b76048f3e3..407617f3307 100644
--- a/spec/lib/gitlab/markdown/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::SyntaxHighlightFilter, lib: true do
+describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
include FilterSpecHelper
it 'highlights valid code blocks' do
diff --git a/spec/lib/gitlab/markdown/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
index c8c79c41847..6a5d003e87f 100644
--- a/spec/lib/gitlab/markdown/filter/table_of_contents_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Markdown::TableOfContentsFilter, lib: true do
+describe Banzai::Filter::TableOfContentsFilter, lib: true do
include FilterSpecHelper
def header(level, text)
diff --git a/spec/lib/gitlab/markdown/filter/task_list_filter_spec.rb b/spec/lib/banzai/filter/task_list_filter_spec.rb
index 1b1714ef882..f2e3a44478d 100644
--- a/spec/lib/gitlab/markdown/filter/task_list_filter_spec.rb
+++ b/spec/lib/banzai/filter/task_list_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::TaskListFilter, lib: true do
+describe Banzai::Filter::TaskListFilter, lib: true do
include FilterSpecHelper
it 'does not apply `task-list` class to non-task lists' do
diff --git a/spec/lib/gitlab/markdown/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 38a007b5bee..3b073a90a95 100644
--- a/spec/lib/gitlab/markdown/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::Markdown::UploadLinkFilter, lib: true do
+describe Banzai::Filter::UploadLinkFilter, lib: true do
def filter(doc, contexts = {})
contexts.reverse_merge!({
project: project
diff --git a/spec/lib/gitlab/markdown/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index 277037cf68a..3534bf97784 100644
--- a/spec/lib/gitlab/markdown/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::UserReferenceFilter, lib: true do
+describe Banzai::Filter::UserReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 3a860899e18..6beb21c6d2b 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -50,7 +50,7 @@ module Gitlab
filtered_html = '<b>ASCII</b>'
allow(Asciidoctor).to receive(:convert).and_return(html)
- expect(Gitlab::Markdown).to receive(:render)
+ expect(Banzai).to receive(:render)
.with(html, context.merge(pipeline: :asciidoc))
.and_return(filtered_html)
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 66dc5d4911d..7d963795e17 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -97,6 +97,16 @@ describe Gitlab::ReferenceExtractor, lib: true do
expect(extracted.first.commit_to).to eq commit
end
+ context 'with an external issue tracker' do
+ let(:project) { create(:jira_project) }
+ subject { described_class.new(project, project.creator) }
+
+ it 'returns JIRA issues for a JIRA-integrated project' do
+ subject.analyze('JIRA-123 and FOOBAR-4567')
+ expect(subject.issues).to eq [JiraIssue.new('JIRA-123', project), JiraIssue.new('FOOBAR-4567', project)]
+ end
+ end
+
context 'with a project with an underscore' do
let(:other_project) { create(:project, path: 'test_project') }
let(:issue) { create(:issue, project: other_project) }
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 96b6f1dbca6..1c22e3cb7c4 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -189,6 +189,12 @@ describe Ci::Build, models: true do
it { is_expected.to eq(98.29) }
end
+
+ context 'using a regex capture' do
+ subject { build.extract_coverage('TOTAL 9926 3489 65%', 'TOTAL\s+\d+\s+\d+\s+(\d{1,3}\%)') }
+
+ it { is_expected.to eq(65) }
+ end
end
describe :variables do
@@ -390,4 +396,68 @@ describe Ci::Build, models: true do
it { is_expected.to include('gitlab-ci-token') }
it { is_expected.to include(project.web_url[7..-1]) }
end
+
+ def create_mr(build, commit, factory: :merge_request, created_at: Time.now)
+ FactoryGirl.create(factory,
+ source_project_id: commit.gl_project_id,
+ target_project_id: commit.gl_project_id,
+ source_branch: build.ref,
+ created_at: created_at)
+ end
+
+ describe :merge_request do
+ context 'when a MR has a reference to the commit' do
+ before do
+ @merge_request = create_mr(build, commit, factory: :merge_request)
+
+ commits = [double(id: commit.sha)]
+ allow(@merge_request).to receive(:commits).and_return(commits)
+ allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
+ end
+
+ it 'returns the single associated MR' do
+ expect(build.merge_request.id).to eq(@merge_request.id)
+ end
+ end
+
+ context 'when there is not a MR referencing the commit' do
+ it 'returns nil' do
+ expect(build.merge_request).to be_nil
+ end
+ end
+
+ context 'when more than one MR have a reference to the commit' do
+ before do
+ @merge_request = create_mr(build, commit, factory: :merge_request)
+ @merge_request.close!
+ @merge_request2 = create_mr(build, commit, factory: :merge_request)
+
+ commits = [double(id: commit.sha)]
+ allow(@merge_request).to receive(:commits).and_return(commits)
+ allow(@merge_request2).to receive(:commits).and_return(commits)
+ allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request, @merge_request2])
+ end
+
+ it 'returns the first MR' do
+ expect(build.merge_request.id).to eq(@merge_request.id)
+ end
+ end
+
+ context 'when a Build is created after the MR' do
+ before do
+ @merge_request = create_mr(build, commit, factory: :merge_request_with_diffs)
+ commit2 = FactoryGirl.create :ci_commit, project: project
+ @build2 = FactoryGirl.create :ci_build, commit: commit2
+
+ commits = [double(id: commit.sha), double(id: commit2.sha)]
+ allow(@merge_request).to receive(:commits).and_return(commits)
+ allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
+ end
+
+ it 'returns the current MR' do
+ expect(@build2.merge_request.id).to eq(@merge_request.id)
+ end
+ end
+
+ end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index ac61c8fb525..b193e16e7f8 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -37,14 +37,14 @@ describe Ci::Commit, models: true do
it 'returns ordered list of commits' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit1])
end
it 'returns commits ordered by committed_at and id, with nulls last' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
- commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
+ commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 6179882e935..6653621a83e 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -1,5 +1,18 @@
require 'spec_helper'
+describe Mentionable do
+ include Mentionable
+
+ describe :references do
+ let(:project) { create(:project) }
+
+ it 'excludes JIRA references' do
+ allow(project).to receive_messages(jira_tracker?: true)
+ expect(referenced_mentionables(project, 'JIRA-123')).to be_empty
+ end
+ end
+end
+
describe Issue, "Mentionable" do
describe '#mentioned_users' do
let!(:user) { create(:user, username: 'stranger') }
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index a9b0b64e5de..30c0a04b840 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
shared_examples 'TokenAuthenticatable' do
describe 'dynamically defined methods' do
- it { expect(described_class).to be_private_method_defined(:generate_token_for) }
+ it { expect(described_class).to be_private_method_defined(:generate_token) }
+ it { expect(described_class).to be_private_method_defined(:write_new_token) }
it { expect(described_class).to respond_to("find_by_#{token_field}") }
it { is_expected.to respond_to("ensure_#{token_field}") }
it { is_expected.to respond_to("reset_#{token_field}!") }
@@ -24,11 +25,11 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
it_behaves_like 'TokenAuthenticatable'
describe 'generating new token' do
- subject { described_class.new }
- let(:token) { subject.send(token_field) }
-
context 'token is not generated yet' do
- it { expect(token).to be nil }
+ describe 'token field accessor' do
+ subject { described_class.new.send(token_field) }
+ it { is_expected.to_not be_blank }
+ end
describe 'ensured token' do
subject { described_class.new.send("ensure_#{token_field}") }
@@ -36,11 +37,21 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
it { is_expected.to be_a String }
it { is_expected.to_not be_blank }
end
+
+ describe 'ensured! token' do
+ subject { described_class.new.send("ensure_#{token_field}!") }
+
+ it 'should persist new token' do
+ expect(subject).to eq described_class.current[token_field]
+ end
+ end
end
context 'token is generated' do
before { subject.send("reset_#{token_field}!") }
- it { expect(token).to be_a String }
+ it 'persists a new token 'do
+ expect(subject.send(:read_attribute, token_field)).to be_a String
+ end
end
end
diff --git a/spec/models/jira_issue_spec.rb b/spec/models/jira_issue_spec.rb
new file mode 100644
index 00000000000..1634265b439
--- /dev/null
+++ b/spec/models/jira_issue_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe JiraIssue do
+ let(:project) { create(:project) }
+ subject { JiraIssue.new('JIRA-123', project) }
+
+ describe 'id' do
+ subject { super().id }
+ it { is_expected.to eq('JIRA-123') }
+ end
+
+ describe 'iid' do
+ subject { super().iid }
+ it { is_expected.to eq('JIRA-123') }
+ end
+
+ describe 'to_s' do
+ subject { super().to_s }
+ it { is_expected.to eq('JIRA-123') }
+ end
+
+ describe :== do
+ specify { expect(subject).to eq(JiraIssue.new('JIRA-123', project)) }
+ specify { expect(subject).not_to eq(JiraIssue.new('JIRA-124', project)) }
+
+ it 'only compares with JiraIssues' do
+ expect(subject).not_to eq('JIRA-123')
+ end
+ end
+end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index d7fe01976d8..c962b83644a 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -81,7 +81,7 @@ describe Key, models: true do
it 'rejects the multiple line key' do
key = build(:key)
- key.key.gsub!(' ', "\n")
+ key.key.tr!(' ', "\n")
expect(key).not_to be_valid
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 1aeba9b2b3b..e0653a8327d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -164,6 +164,17 @@ describe MergeRequest, models: true do
expect(subject.closes_issues).to include(issue2)
end
+
+ context 'for a project with JIRA integration' do
+ let(:issue0) { JiraIssue.new('JIRA-123', subject.project) }
+ let(:issue1) { JiraIssue.new('FOOBAR-4567', subject.project) }
+
+ it 'returns sorted JiraIssues' do
+ allow(subject.project).to receive_messages(default_branch: subject.target_branch)
+
+ expect(subject.closes_issues).to eq([issue0, issue1])
+ end
+ end
end
describe "#work_in_progress?" do
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 216c7dabae0..b7006fa5e68 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -164,8 +164,8 @@ describe Note, models: true do
let(:issue) { create :issue }
it "converts aliases to actual name" do
- note = create :note, note: ":thumbsup:", noteable: issue
- expect(note.reload.note).to eq("+1")
+ note = create :note, note: ":+1:", noteable: issue
+ expect(note.reload.note).to eq("thumbsup")
end
end
end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index a5662b08bda..91dd92b7c67 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -57,23 +57,21 @@ describe HipchatService, models: true do
it 'should use v1 if version is provided' do
allow(hipchat).to receive(:api_version).and_return('v1')
- expect(HipChat::Client).to receive(:new).
- with(token,
- api_version: 'v1',
- server_url: server_url).
- and_return(
- double(:hipchat_service).as_null_object)
+ expect(HipChat::Client).to receive(:new).with(
+ token,
+ api_version: 'v1',
+ server_url: server_url
+ ).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
it 'should use v2 as the version when nothing is provided' do
allow(hipchat).to receive(:api_version).and_return('')
- expect(HipChat::Client).to receive(:new).
- with(token,
- api_version: 'v2',
- server_url: server_url).
- and_return(
- double(:hipchat_service).as_null_object)
+ expect(HipChat::Client).to receive(:new).with(
+ token,
+ api_version: 'v2',
+ server_url: server_url
+ ).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 7d91ebe9ce6..2f8193170ae 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -26,6 +26,113 @@ describe JiraService, models: true do
it { is_expected.to have_one :service_hook }
end
+ describe "Execute" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:merge_request) { create(:merge_request) }
+
+ before do
+ @jira_service = JiraService.new
+ allow(@jira_service).to receive_messages(
+ project_id: project.id,
+ project: project,
+ service_hook: true,
+ project_url: 'http://jira.example.com',
+ username: 'gitlab_jira_username',
+ password: 'gitlab_jira_password'
+ )
+ @jira_service.save # will build API URL, as api_url was not specified above
+ @sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
+ # https://github.com/bblimke/webmock#request-with-basic-authentication
+ @api_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/transitions'
+ @comment_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/comment'
+
+ WebMock.stub_request(:post, @api_url)
+ WebMock.stub_request(:post, @comment_url)
+ end
+
+ it "should call JIRA API" do
+ @jira_service.execute(merge_request, JiraIssue.new("JIRA-123", project))
+ expect(WebMock).to have_requested(:post, @comment_url).with(
+ body: /Issue solved with/
+ ).once
+ end
+
+ it "calls the api with jira_issue_transition_id" do
+ @jira_service.jira_issue_transition_id = 'this-is-a-custom-id'
+ @jira_service.execute(merge_request, JiraIssue.new("JIRA-123", project))
+ expect(WebMock).to have_requested(:post, @api_url).with(
+ body: /this-is-a-custom-id/
+ ).once
+ end
+ end
+
+ describe "Stored password invalidation" do
+ let(:project) { create(:project) }
+
+ context "when a password was previously set" do
+ before do
+ @jira_service = JiraService.create(
+ project: create(:project),
+ properties: {
+ api_url: 'http://jira.example.com/rest/api/2',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+ it "reset password if url changed" do
+ @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+ @jira_service.save
+ expect(@jira_service.password).to be_nil
+ end
+
+ it "does not reset password if username changed" do
+ @jira_service.username = "some_name"
+ @jira_service.save
+ expect(@jira_service.password).to eq("password")
+ end
+
+ it "does not reset password if new url is set together with password, even if it's the same password" do
+ @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+ @jira_service.password = 'password'
+ @jira_service.save
+ expect(@jira_service.password).to eq("password")
+ expect(@jira_service.api_url).to eq("http://jira_edited.example.com/rest/api/2")
+ end
+
+ it "should reset password if url changed, even if setter called multiple times" do
+ @jira_service.api_url = 'http://jira1.example.com/rest/api/2'
+ @jira_service.api_url = 'http://jira1.example.com/rest/api/2'
+ @jira_service.save
+ expect(@jira_service.password).to be_nil
+ end
+ end
+
+ context "when no password was previously set" do
+ before do
+ @jira_service = JiraService.create(
+ project: create(:project),
+ properties: {
+ api_url: 'http://jira.example.com/rest/api/2',
+ username: 'mic'
+ }
+ )
+ end
+
+ it "saves password if new url is set together with password" do
+ @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+ @jira_service.password = 'password'
+ @jira_service.save
+ expect(@jira_service.password).to eq("password")
+ expect(@jira_service.api_url).to eq("http://jira_edited.example.com/rest/api/2")
+ end
+
+ end
+ end
+
+
describe "Validations" do
context "active" do
before do
@@ -78,11 +185,12 @@ describe JiraService, models: true do
context 'when gitlab.yml was initialized' do
before do
- settings = { "jira" => {
- "title" => "Jira",
- "project_url" => "http://jira.sample/projects/project_a",
- "issues_url" => "http://jira.sample/issues/:id",
- "new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
+ settings = {
+ "jira" => {
+ "title" => "Jira",
+ "project_url" => "http://jira.sample/projects/project_a",
+ "issues_url" => "http://jira.sample/issues/:id",
+ "new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
}
}
allow(Gitlab.config).to receive(:issues_tracker).and_return(settings)
diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/slack_service/note_message_spec.rb
index ebf8837570e..06006b9a4f5 100644
--- a/spec/models/project_services/slack_service/note_message_spec.rb
+++ b/spec/models/project_services/slack_service/note_message_spec.rb
@@ -89,10 +89,10 @@ describe SlackService::NoteMessage, models: true do
it 'returns a message regarding notes on an issue' do
message = SlackService::NoteMessage.new(@args)
expect(message.pretext).to eq(
- "Test User commented on " \
- "<url|issue #20> in <somewhere.com|project_name>: " \
- "*issue title*")
- expected_attachments = [
+ "Test User commented on " \
+ "<url|issue #20> in <somewhere.com|project_name>: " \
+ "*issue title*")
+ expected_attachments = [
{
text: "comment on an issue",
color: color,
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 87582e07494..c4d3813e9c9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -172,13 +172,17 @@ describe Project, models: true do
describe '#get_issue' do
let(:project) { create(:empty_project) }
- let(:issue) { create(:issue, project: project) }
+ let!(:issue) { create(:issue, project: project) }
context 'with default issues tracker' do
it 'returns an issue' do
expect(project.get_issue(issue.iid)).to eq issue
end
+ it 'returns count of open issues' do
+ expect(project.open_issues_count).to eq(1)
+ end
+
it 'returns nil when no issue found' do
expect(project.get_issue(999)).to be_nil
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index daa9d1087bf..2f184bbaf92 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -26,6 +26,7 @@
# bio :string(255)
# failed_attempts :integer default(0)
# locked_at :datetime
+# unlock_token :string(255)
# username :string(255)
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
@@ -462,8 +463,8 @@ describe User, models: true do
expect(User.search(user1.username.downcase).to_a).to eq([user1])
expect(User.search(user2.username.upcase).to_a).to eq([user2])
expect(User.search(user2.username.downcase).to_a).to eq([user2])
- expect(User.search(user1.username.downcase).to_a.count).to eq(2)
- expect(User.search(user2.username.downcase).to_a.count).to eq(1)
+ expect(User.search(user1.username.downcase).to_a.size).to eq(2)
+ expect(User.search(user2.username.downcase).to_a.size).to eq(1)
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index a91fa735321..e194eb93cf4 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -6,7 +6,7 @@ describe API::API, api: true do
let(:user) { create(:user) }
let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
- let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.seconds) }
+ let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds) }
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index e784b7d1f2d..7f0f9454b10 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -65,6 +65,22 @@ describe API::API, api: true do
expect(json_response.first.keys).to include('tag_list')
end
+ it 'should include open_issues_count' do
+ get api('/projects', user)
+ expect(response.status).to eq 200
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).to include('open_issues_count')
+ end
+
+ it 'should not include open_issues_count' do
+ project.update_attributes( { issues_enabled: false } )
+
+ get api('/projects', user)
+ expect(response.status).to eq 200
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).not_to include('open_issues_count')
+ end
+
context 'and using search' do
it 'should return searched project' do
get api('/projects', user), { search: project.name }
@@ -115,6 +131,7 @@ describe API::API, api: true do
expect(json_response).to satisfy do |response|
response.one? do |entry|
+ entry.has_key?('permissions') &&
entry['name'] == project.name &&
entry['owner']['username'] == user.username
end
@@ -123,6 +140,25 @@ describe API::API, api: true do
end
end
+ describe 'GET /projects/starred' do
+ before do
+ admin.starred_projects << project
+ admin.save!
+ end
+
+ it 'should return the starred projects' do
+ get api('/projects/all', admin)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+
+ expect(json_response).to satisfy do |response|
+ response.one? do |entry|
+ entry['name'] == project.name
+ end
+ end
+ end
+ end
+
describe 'POST /projects' do
context 'maximum number of projects reached' do
it 'should not create new project and respond with 403' do
@@ -347,6 +383,18 @@ describe API::API, api: true do
end
describe 'permissions' do
+ context 'all projects' do
+ it 'Contains permission information' do
+ project.team << [user, :master]
+ get api("/projects", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response.first['permissions']['project_access']['access_level']).
+ to eq(Gitlab::Access::MASTER)
+ expect(json_response.first['permissions']['group_access']).to be_nil
+ end
+ end
+
context 'personal project' do
it 'Sets project access and returns 200' do
project.team << [user, :master]
@@ -455,7 +503,7 @@ describe API::API, api: true do
end
end
- describe 'PUT /projects/:id/snippets/:shippet_id' do
+ describe 'PUT /projects/:id/snippets/:snippet_id' do
it 'should update an existing project snippet' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
code: 'updated code'
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index b180d2fec77..fed9ae1949b 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -29,7 +29,7 @@ describe API::API, api: true do
if required_attributes.empty?
expected_code = 200
else
- attrs.delete(required_attributes.shuffle.first)
+ attrs.delete(required_attributes.sample)
expected_code = 400
end
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 567da013e6f..5942aa7a1b5 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -8,7 +8,6 @@ describe Ci::API::API do
before do
stub_gitlab_calls
- stub_application_setting(ensure_runners_registration_token: registration_token)
stub_application_setting(runners_registration_token: registration_token)
end
diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb
index 798c480b81a..ea5dcfa068a 100644
--- a/spec/services/create_commit_builds_service_spec.rb
+++ b/spec/services/create_commit_builds_service_spec.rb
@@ -17,7 +17,7 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: [{ message: "Message" }]
- )
+ )
end
it { expect(commit).to be_kind_of(Ci::Commit) }
@@ -34,7 +34,7 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: [{ message: "Message" }]
- )
+ )
expect(result).to be_persisted
end
@@ -47,26 +47,24 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: [{ message: "Message" }]
- )
+ )
expect(result).to be_persisted
end
end
- it 'skips commits without .gitlab-ci.yml' do
+ it 'skips creating ci_commit for refs without .gitlab-ci.yml' do
stub_ci_commit_yaml_file(nil)
result = service.execute(project, user,
ref: 'refs/heads/0_1',
before: '00000000',
after: '31das312',
commits: [{ message: 'Message' }]
- )
- expect(result).to be_persisted
- expect(result.builds.any?).to be_falsey
- expect(result.status).to eq('skipped')
- expect(result.yaml_errors).to be_nil
+ )
+ expect(result).to be_falsey
+ expect(Ci::Commit.count).to eq(0)
end
- it 'skips commits if yaml is invalid' do
+ it 'fails commits if yaml is invalid' do
message = 'message'
allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
stub_ci_commit_yaml_file('invalid: file: file')
@@ -76,7 +74,8 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.any?).to be false
expect(commit.status).to eq('failed')
expect(commit.yaml_errors).to_not be_nil
@@ -96,7 +95,8 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.any?).to be false
expect(commit.status).to eq("skipped")
end
@@ -110,8 +110,9 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.first.name).to eq("staging")
end
@@ -123,7 +124,8 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.any?).to be false
expect(commit.status).to eq("skipped")
expect(commit.yaml_errors).to be_nil
@@ -139,7 +141,8 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.count(:all)).to eq(2)
commit = service.execute(project, user,
@@ -147,7 +150,8 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.builds.count(:all)).to eq(2)
end
@@ -161,8 +165,9 @@ describe CreateCommitBuildsService, services: true do
before: '00000000',
after: '31das312',
commits: commits
- )
+ )
+ expect(commit).to be_persisted
expect(commit.status).to eq("failed")
expect(commit.builds.any?).to be false
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index a04c242cf0e..c1080ef190a 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -265,6 +265,75 @@ describe GitPushService, services: true do
expect(Issue.find(issue.id)).to be_opened
end
end
+
+ # EE-only tests
+ context "for jira issue tracker" do
+ include JiraServiceHelper
+
+ let(:jira_tracker) { project.create_jira_service if project.jira_service.nil? }
+
+ before do
+ jira_service_settings
+
+ WebMock.stub_request(:post, jira_api_transition_url)
+ WebMock.stub_request(:post, jira_api_comment_url)
+ WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+ WebMock.stub_request(:get, jira_api_test_url)
+
+ allow(closing_commit).to receive_messages({
+ issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
+ safe_message: message,
+ author_name: commit_author.name,
+ author_email: commit_author.email
+ })
+
+ allow(project.repository).to receive_messages(commits_between: [closing_commit])
+ end
+
+ after do
+ jira_tracker.destroy!
+ end
+
+ context "mentioning an issue" do
+ let(:message) { "this is some work.\n\nrelated to JIRA-1" }
+
+ it "should initiate one api call to jira server to mention the issue" do
+ service.execute(project, user, @oldrev, @newrev, @ref)
+
+ expect(WebMock).to have_requested(:post, jira_api_comment_url).with(
+ body: /mentioned this issue in/
+ ).once
+ end
+ end
+
+ context "closing an issue" do
+ let(:message) { "this is some work.\n\ncloses JIRA-1" }
+
+ it "should initiate one api call to jira server to close the issue" do
+ transition_body = {
+ transition: {
+ id: '2'
+ }
+ }.to_json
+
+ service.execute(project, user, @oldrev, @newrev, @ref)
+ expect(WebMock).to have_requested(:post, jira_api_transition_url).with(
+ body: transition_body
+ ).once
+ end
+
+ it "should initiate one api call to jira server to comment on the issue" do
+ comment_body = {
+ body: "Issue solved with [#{closing_commit.id}|http://localhost/#{project.path_with_namespace}/commit/#{closing_commit.id}]."
+ }.to_json
+
+ service.execute(project, user, @oldrev, @newrev, @ref)
+ expect(WebMock).to have_requested(:post, jira_api_comment_url).with(
+ body: comment_body
+ ).once
+ end
+ end
+ end
end
describe "empty project" do
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index e2d15f1a83d..b982274c529 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -58,14 +58,14 @@ describe GitTagPushService, services: true do
it { is_expected.to include(timestamp: @commit.date.xmlschema) }
it do
is_expected.to include(
- url: [
- Gitlab.config.gitlab.url,
- project.namespace.to_param,
- project.to_param,
- 'commit',
- @commit.id
- ].join('/')
- )
+ url: [
+ Gitlab.config.gitlab.url,
+ project.namespace.to_param,
+ project.to_param,
+ 'commit',
+ @commit.id
+ ].join('/')
+ )
end
context "with a author" do
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 0a4f9b230e8..c9f828ae2f7 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -425,4 +425,65 @@ describe SystemNoteService, services: true do
end
end
end
+
+ include JiraServiceHelper
+
+ describe 'JIRA integration' do
+ let(:project) { create(:project) }
+ let(:author) { create(:user) }
+ let(:issue) { create(:issue, project: project) }
+ let(:mergereq) { create(:merge_request, :simple, target_project: project, source_project: project) }
+ let(:jira_issue) { JiraIssue.new("JIRA-1", project)}
+ let(:jira_tracker) { project.create_jira_service if project.jira_service.nil? }
+ let(:commit) { project.commit }
+
+ context 'in JIRA issue tracker' do
+ before do
+ jira_service_settings
+ WebMock.stub_request(:post, jira_api_comment_url)
+ end
+
+ after do
+ jira_tracker.destroy!
+ end
+
+ describe "new reference" do
+ before do
+ WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+ end
+
+ subject { described_class.cross_reference(jira_issue, commit, author) }
+
+ it { is_expected.to eq(jira_status_message) }
+ end
+
+ describe "existing reference" do
+ before do
+ message = "[#{author.name}|http://localhost/u/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]."
+ WebMock.stub_request(:get, jira_api_comment_url).to_return(body: "{\"comments\":[{\"body\":\"#{message}\"}]}")
+ end
+
+ subject { described_class.cross_reference(jira_issue, commit, author) }
+ it { is_expected.not_to eq(jira_status_message) }
+ end
+ end
+
+ context 'issue from an issue' do
+ context 'in JIRA issue tracker' do
+ before do
+ jira_service_settings
+ WebMock.stub_request(:post, jira_api_comment_url)
+ WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+ end
+
+ after do
+ jira_tracker.destroy!
+ end
+
+ subject { described_class.cross_reference(jira_issue, issue, author) }
+
+ it { is_expected.to eq(jira_status_message) }
+ end
+ end
+ end
end
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
index 124bb76e678..48d114896d0 100644
--- a/spec/services/update_snippet_service_spec.rb
+++ b/spec/services/update_snippet_service_spec.rb
@@ -42,7 +42,7 @@ describe UpdateSnippetService, services: true do
CreateSnippetService.new(project, user, opts).execute
end
- def update_snippet(project = nil, user, snippet, opts)
+ def update_snippet(project, user, snippet, opts)
UpdateSnippetService.new(project, user, snippet, opts).execute
end
end
diff --git a/spec/support/filter_spec_helper.rb b/spec/support/filter_spec_helper.rb
index 91e3bee13c1..d6e03cbef3d 100644
--- a/spec/support/filter_spec_helper.rb
+++ b/spec/support/filter_spec_helper.rb
@@ -1,4 +1,4 @@
-# Helper methods for Gitlab::Markdown filter specs
+# Helper methods for Banzai filter specs
#
# Must be included into specs manually
module FilterSpecHelper
@@ -10,49 +10,49 @@ module FilterSpecHelper
# if none is provided.
#
# html - HTML String to pass to the filter's `call` method.
- # contexts - Hash context for the filter. (default: {project: project})
+ # context - Hash context for the filter. (default: {project: project})
#
# Returns a Nokogiri::XML::DocumentFragment
- def filter(html, contexts = {})
+ def filter(html, context = {})
if defined?(project)
- contexts.reverse_merge!(project: project)
+ context.reverse_merge!(project: project)
end
- described_class.call(html, contexts)
+ described_class.call(html, context)
end
# Run text through HTML::Pipeline with the current filter and return the
# result Hash
#
# body - String text to run through the pipeline
- # contexts - Hash context for the filter. (default: {project: project})
+ # context - Hash context for the filter. (default: {project: project})
#
# Returns the Hash
- def pipeline_result(body, contexts = {})
- contexts.reverse_merge!(project: project) if defined?(project)
+ def pipeline_result(body, context = {})
+ context.reverse_merge!(project: project) if defined?(project)
- pipeline = HTML::Pipeline.new([described_class], contexts)
+ pipeline = HTML::Pipeline.new([described_class], context)
pipeline.call(body)
end
- def reference_pipeline(contexts = {})
- contexts.reverse_merge!(project: project) if defined?(project)
+ def reference_pipeline(context = {})
+ context.reverse_merge!(project: project) if defined?(project)
filters = [
- Gitlab::Markdown::AutolinkFilter,
+ Banzai::Filter::AutolinkFilter,
described_class,
- Gitlab::Markdown::ReferenceGathererFilter
+ Banzai::Filter::ReferenceGathererFilter
]
- HTML::Pipeline.new(filters, contexts)
+ HTML::Pipeline.new(filters, context)
end
- def reference_pipeline_result(body, contexts = {})
- reference_pipeline(contexts).call(body)
+ def reference_pipeline_result(body, context = {})
+ reference_pipeline(context).call(body)
end
- def reference_filter(html, contexts = {})
- reference_pipeline(contexts).to_document(html)
+ def reference_filter(html, context = {})
+ reference_pipeline(context).to_document(html)
end
# Modify a String reference to make it invalid
diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb
new file mode 100644
index 00000000000..a3f496359b1
--- /dev/null
+++ b/spec/support/jira_service_helper.rb
@@ -0,0 +1,67 @@
+module JiraServiceHelper
+
+ def jira_service_settings
+ properties = {
+ "title"=>"JIRA tracker",
+ "project_url"=>"http://jira.example/issues/?jql=project=A",
+ "issues_url"=>"http://jira.example/browse/JIRA-1",
+ "new_issue_url"=>"http://jira.example/secure/CreateIssue.jspa",
+ "api_url"=>"http://jira.example/rest/api/2"
+ }
+
+ jira_tracker.update_attributes(properties: properties, active: true)
+ end
+
+ def jira_status_message
+ "JiraService SUCCESS 200: Successfully posted to #{jira_api_comment_url}."
+ end
+
+ def jira_issue_comments
+ "{\"startAt\":0,\"maxResults\":11,\"total\":11,
+ \"comments\":[{\"self\":\"http://0.0.0.0:4567/rest/api/2/issue/10002/comment/10609\",
+ \"id\":\"10609\",\"author\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",
+ \"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+ \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+ \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+ \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+ \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},
+ \"displayName\":\"GitLab\",\"active\":true},
+ \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned JIRA-1 in Merge request of [gitlab-org/gitlab-test|http://localhost:3000/gitlab-org/gitlab-test/merge_requests/2].\",
+ \"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+ \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+ \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+ \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+ \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+ \"created\":\"2015-02-12T22:47:07.826+0100\",
+ \"updated\":\"2015-02-12T22:47:07.826+0100\"},
+ {\"self\":\"http://0.0.0.0:4567/rest/api/2/issue/10002/comment/10700\",
+ \"id\":\"10700\",\"author\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",
+ \"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+ \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+ \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+ \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+ \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+ \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned this issue in [a commit of h5bp/html5-boilerplate|http://localhost:3000/h5bp/html5-boilerplate/commit/2439f77897122fbeee3bfd9bb692d3608848433e].\",
+ \"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+ \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+ \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+ \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+ \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+ \"created\":\"2015-04-01T03:45:55.667+0200\",
+ \"updated\":\"2015-04-01T03:45:55.667+0200\"
+ }
+ ]}"
+ end
+
+ def jira_api_comment_url
+ 'http://jira.example/rest/api/2/issue/JIRA-1/comment'
+ end
+
+ def jira_api_transition_url
+ 'http://jira.example/rest/api/2/issue/JIRA-1/transitions'
+ end
+
+ def jira_api_test_url
+ 'http://jira.example/rest/api/2/myself'
+ end
+end
diff --git a/spec/support/repo_helpers.rb b/spec/support/repo_helpers.rb
index aadf791bf3f..aa8258d6dad 100644
--- a/spec/support/repo_helpers.rb
+++ b/spec/support/repo_helpers.rb
@@ -45,12 +45,12 @@ eos
def another_sample_commit
OpenStruct.new(
- id: "e56497bb5f03a90a51293fc6d516788730953899",
- parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
- author_full_name: "Sytse Sijbrandij",
- author_email: "sytse@gitlab.com",
- files_changed_count: 1,
- message: <<eos
+ id: "e56497bb5f03a90a51293fc6d516788730953899",
+ parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
+ author_full_name: "Sytse Sijbrandij",
+ author_email: "sytse@gitlab.com",
+ files_changed_count: 1,
+ message: <<eos
Add directory structure for tree_helper spec
This directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 245f066df1f..dae31992620 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -9,20 +9,22 @@ describe RepositoryForkWorker do
describe "#perform" do
it "creates a new repository from a fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).with(
- project.path_with_namespace,
- fork_project.namespace.path).
- and_return(true)
+ project.path_with_namespace,
+ fork_project.namespace.path
+ ).and_return(true)
- subject.perform(project.id,
- project.path_with_namespace,
- fork_project.namespace.path)
+ subject.perform(
+ project.id,
+ project.path_with_namespace,
+ fork_project.namespace.path)
end
it "handles bad fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_return(false)
- subject.perform(project.id,
- project.path_with_namespace,
- fork_project.namespace.path)
+ subject.perform(
+ project.id,
+ project.path_with_namespace,
+ fork_project.namespace.path)
end
end
end
diff --git a/spec/workers/stuck_ci_builds_worker_spec.rb b/spec/workers/stuck_ci_builds_worker_spec.rb
index f9d87d97014..665ec20f224 100644
--- a/spec/workers/stuck_ci_builds_worker_spec.rb
+++ b/spec/workers/stuck_ci_builds_worker_spec.rb
@@ -15,7 +15,7 @@ describe StuckCiBuildsWorker do
end
it 'gets dropped if it was updated over 2 days ago' do
- build.update!(updated_at: 2.day.ago)
+ build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform
is_expected.to eq('failed')
end
@@ -35,7 +35,7 @@ describe StuckCiBuildsWorker do
end
it "is still #{status}" do
- build.update!(updated_at: 2.day.ago)
+ build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform
is_expected.to eq(status)
end