Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-04-13 15:47:17 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-04-13 15:47:17 +0300
commit87cd46c475c8d6f79abae1be786576f22369c711 (patch)
tree9f7d76ae61b81f70d048276455c44f97589ccbc7
parent941cfd1fbd576c07d82e18d9d7b206fc8245244b (diff)
parent59c735bd1efe13405a7cdc11d9617be09d599266 (diff)
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce
-rw-r--r--CHANGELOG18
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock8
-rw-r--r--app/assets/javascripts/application.js.coffee3
-rw-r--r--app/assets/javascripts/behaviors/requires_input.js.coffee16
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee4
-rw-r--r--app/assets/javascripts/lib/datetime_utility.js.coffee17
-rw-r--r--app/assets/javascripts/lib/notify.js.coffee5
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee6
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee35
-rw-r--r--app/assets/javascripts/notes.js.coffee14
-rw-r--r--app/assets/javascripts/profile.js.coffee7
-rw-r--r--app/assets/javascripts/project.js.coffee17
-rw-r--r--app/assets/javascripts/project_select.js.coffee32
-rw-r--r--app/assets/javascripts/todos.js.coffee2
-rw-r--r--app/assets/stylesheets/framework/header.scss5
-rw-r--r--app/assets/stylesheets/framework/nav.scss6
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/events.scss11
-rw-r--r--app/assets/stylesheets/pages/issuable.scss6
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss1
-rw-r--r--app/assets/stylesheets/pages/note_form.scss14
-rw-r--r--app/assets/stylesheets/pages/notes.scss26
-rw-r--r--app/assets/stylesheets/pages/todos.scss5
-rw-r--r--app/controllers/groups/notification_settings_controller.rb16
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb26
-rw-r--r--app/controllers/profiles/notifications_controller.rb37
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb3
-rw-r--r--app/controllers/projects/notification_settings_controller.rb16
-rw-r--r--app/controllers/projects_controller.rb12
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/namespaces_helper.rb12
-rw-r--r--app/helpers/notifications_helper.rb68
-rw-r--r--app/helpers/projects_helper.rb17
-rw-r--r--app/helpers/todos_helper.rb2
-rw-r--r--app/models/commit.rb8
-rw-r--r--app/models/concerns/notifiable.rb15
-rw-r--r--app/models/group.rb1
-rw-r--r--app/models/member.rb12
-rw-r--r--app/models/members/group_member.rb1
-rw-r--r--app/models/members/project_member.rb1
-rw-r--r--app/models/merge_request.rb6
-rw-r--r--app/models/notification.rb77
-rw-r--r--app/models/notification_setting.rb28
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/repository.rb8
-rw-r--r--app/models/user.rb18
-rw-r--r--app/services/notes/delete_service.rb8
-rw-r--r--app/services/notification_service.rb52
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/layouts/project.html.haml8
-rw-r--r--app/views/profiles/notifications/_group_settings.html.haml13
-rw-r--r--app/views/profiles/notifications/_project_settings.html.haml13
-rw-r--r--app/views/profiles/notifications/_settings.html.haml17
-rw-r--r--app/views/profiles/notifications/show.html.haml103
-rw-r--r--app/views/profiles/notifications/update.js.haml6
-rw-r--r--app/views/projects/buttons/_notifications.html.haml21
-rw-r--r--app/views/projects/merge_requests/_form.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/_show.html.haml16
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/projects/notes/_note.html.haml12
-rw-r--r--app/views/shared/_commit_message_container.html.haml2
-rw-r--r--config/gitlab.yml.example9
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--config/initializers/metrics.rb15
-rw-r--r--config/initializers/trusted_proxies.rb2
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/20160328112808_create_notification_settings.rb11
-rw-r--r--db/migrate/20160328115649_migrate_new_notification_setting.rb17
-rw-r--r--db/migrate/20160328121138_add_notification_setting_index.rb6
-rw-r--r--db/schema.rb12
-rw-r--r--doc/README.md2
-rw-r--r--doc/api/groups.md81
-rw-r--r--doc/api/issues.md55
-rw-r--r--doc/api/notes.md141
-rw-r--r--doc/api/projects.md6
-rw-r--r--doc/api/tags.md46
-rw-r--r--doc/install/installation.md10
-rw-r--r--doc/project_services/img/jira_service_page.pngbin35496 -> 49122 bytes
-rw-r--r--doc/project_services/jira.md22
-rw-r--r--doc/workflow/img/new_branch_from_issue.pngbin0 -> 120622 bytes
-rw-r--r--doc/workflow/web_editor.md32
-rw-r--r--features/profile/notifications.feature6
-rw-r--r--features/steps/profile/notifications.rb10
-rw-r--r--fixtures/emojis/digests.json2485
-rw-r--r--lib/api/entities.rb15
-rw-r--r--lib/api/groups.rb28
-rw-r--r--lib/api/helpers.rb3
-rw-r--r--lib/api/issues.rb23
-rw-r--r--lib/api/notes.rb17
-rw-r--r--lib/api/project_members.rb13
-rw-r--r--lib/api/tags.rb14
-rw-r--r--lib/gitlab.rb3
-rw-r--r--lib/gitlab/metrics.rb10
-rw-r--r--lib/gitlab/saml/user.rb3
-rw-r--r--lib/tasks/gemojione.rake15
-rw-r--r--spec/controllers/groups/notification_settings_controller_spec.rb32
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb28
-rw-r--r--spec/controllers/projects/notification_settings_controller_spec.rb38
-rw-r--r--spec/features/merge_requests/edit_mr_spec.rb21
-rw-r--r--spec/features/projects_spec.rb3
-rw-r--r--spec/helpers/notifications_helper_spec.rb37
-rw-r--r--spec/javascripts/fixtures/project_title.html.haml27
-rw-r--r--spec/javascripts/project_title_spec.js.coffee20
-rw-r--r--spec/lib/gitlab/metrics_spec.rb25
-rw-r--r--spec/lib/gitlab_spec.rb17
-rw-r--r--spec/models/notification_setting_spec.rb17
-rw-r--r--spec/models/repository_spec.rb2
-rw-r--r--spec/requests/api/group_members_spec.rb12
-rw-r--r--spec/requests/api/groups_spec.rb57
-rw-r--r--spec/requests/api/issues_spec.rb70
-rw-r--r--spec/requests/api/notes_spec.rb61
-rw-r--r--spec/requests/api/project_members_spec.rb20
-rw-r--r--spec/requests/api/tags_spec.rb17
-rw-r--r--spec/services/notes/delete_service_spec.rb15
-rw-r--r--spec/services/notification_service_spec.rb29
-rw-r--r--vendor/assets/javascripts/date.format.js125
118 files changed, 4246 insertions, 481 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 593e8f77ab4..ed59bc1b252 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,10 +1,14 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.7.0 (unreleased)
+ - All service classes (those residing in app/services) are now instrumented (Yorick Peterse)
+ - Developers can now add custom tags to transactions (Yorick Peterse)
- Enable gzip for assets, makes the page size significantly smaller. !3544 / !3632 (Connor Shea)
- Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea)
- All images in discussions and wikis now link to their source files !3464 (Connor Shea).
- Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu)
+ - Add setting for customizing the list of trusted proxies !3524
+ - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524
- Improved Markdown rendering performance !3389 (Yorick Peterse)
- Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
- Expose project badges in project settings
@@ -12,6 +16,8 @@ v 8.7.0 (unreleased)
- Make HTTP(s) label consistent on clone bar (Stan Hu)
- Expose label description in API (Mariusz Jachimowicz)
- Allow back dating on issues when created through the API
+ - API: Ability to update a group (Robert Schilling)
+ - API: Ability to move issues (Robert Schilling)
- Fix Error 500 after renaming a project path (Stan Hu)
- Fix avatar stretching by providing a cropping feature
- API: Expose `subscribed` for issues and merge requests (Robert Schilling)
@@ -21,22 +27,34 @@ v 8.7.0 (unreleased)
- Handle nil descriptions in Slack issue messages (Stan Hu)
- API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling)
- Add default scope to projects to exclude projects pending deletion
+ - Allow to close merge requests which source projects(forks) are deleted.
- Ensure empty recipients are rejected in BuildsEmailService
- API: Ability to filter milestones by state `active` and `closed` (Robert Schilling)
- API: Fix milestone filtering by `iid` (Robert Schilling)
+ - API: Delete notes of issues, snippets, and merge requests (Robert Schilling)
- Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.)
- Better errors handling when creating milestones inside groups
+ - Hide `Create a group` help block when creating a new project in a group
- Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.)
- Gracefully handle notes on deleted commits in merge requests (Stan Hu)
+ - Decouple membership and notifications
- Fix creation of merge requests for orphaned branches (Stan Hu)
+ - API: Ability to retrieve a single tag (Robert Schilling)
- Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla)
- Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
- Fix admin/projects when using visibility levels on search (PotHix)
- Build status notifications
- API: Expose user location (Robert Schilling)
+ - API: Do not leak group existence via return code (Robert Schilling)
- ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591
- Update number of Todos in the sidebar when it's marked as "Done". !3600
- API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling)
+ - API: User can leave a project through the API when not master or owner. !3613
+ - Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu)
+
+v 8.6.6
+ - Fix error on language detection when repository has no HEAD (e.g., master branch). !3654 (Jeroen Bobbeldijk)
+ - Project switcher uses new dropdown styling
v 8.6.5
- Fix importing from GitHub Enterprise. !3529
diff --git a/Gemfile b/Gemfile
index 258b5612cd5..199ef65d922 100644
--- a/Gemfile
+++ b/Gemfile
@@ -285,9 +285,9 @@ group :development, :test do
gem 'teaspoon', '~> 1.1.0'
gem 'teaspoon-jasmine', '~> 2.2.0'
- gem 'spring', '~> 1.6.4'
+ gem 'spring', '~> 1.7.0'
gem 'spring-commands-rspec', '~> 1.0.4'
- gem 'spring-commands-spinach', '~> 1.0.0'
+ gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.38.0', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 9da44a46583..ad7d7c18559 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -769,10 +769,10 @@ GEM
spinach (>= 0.4)
spinach-rerun-reporter (0.0.2)
spinach (~> 0.8)
- spring (1.6.4)
+ spring (1.7.1)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
- spring-commands-spinach (1.0.0)
+ spring-commands-spinach (1.1.0)
spring (>= 0.9.1)
spring-commands-teaspoon (0.0.2)
spring (>= 0.9.1)
@@ -1030,9 +1030,9 @@ DEPENDENCIES
slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
- spring (~> 1.6.4)
+ spring (~> 1.7.0)
spring-commands-rspec (~> 1.0.4)
- spring-commands-spinach (~> 1.0.0)
+ spring-commands-spinach (~> 1.1.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.6.0)
state_machines-activerecord (~> 0.3.0)
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index f01c67e9474..b05138ac1ac 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -41,6 +41,7 @@
#= require shortcuts_issuable
#= require shortcuts_network
#= require jquery.nicescroll
+#= require date.format
#= require_tree .
#= require fuzzaldrin-plus
#= require cropper
@@ -163,7 +164,7 @@ $ ->
$('.trigger-submit').on 'change', ->
$(@).parents('form').submit()
- $('abbr.timeago, .js-timeago').timeago()
+ gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), false)
# Flash
if (flash = $(".flash-container")).length > 0
diff --git a/app/assets/javascripts/behaviors/requires_input.js.coffee b/app/assets/javascripts/behaviors/requires_input.js.coffee
index 79d750d1847..0faa570ce13 100644
--- a/app/assets/javascripts/behaviors/requires_input.js.coffee
+++ b/app/assets/javascripts/behaviors/requires_input.js.coffee
@@ -35,4 +35,18 @@ $.fn.requiresInput = ->
$form.on 'change input', fieldSelector, requireInput
$ ->
- $('form.js-requires-input').requiresInput()
+ $form = $('form.js-requires-input')
+ $form.requiresInput()
+
+ # Hide or Show the help block when creating a new project
+ # based on the option selected
+ hideOrShowHelpBlock = (form) ->
+ selected = $('.js-select-namespace option:selected')
+ if selected.length and selected.data('options-parent') is 'groups'
+ return form.find('.help-block').hide()
+ else if selected.length
+ form.find('.help-block').show()
+
+ hideOrShowHelpBlock($form)
+
+ $('.select2.js-select-namespace').change -> hideOrShowHelpBlock($form)
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index ee1d0fad289..2dc37257e22 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -122,7 +122,9 @@ class GitLabDropdown
FILTER_INPUT = '.dropdown-input .dropdown-input-field'
constructor: (@el, @options) ->
- @dropdown = $(@el).parent()
+ self = @
+ selector = $(@el).data "target"
+ @dropdown = if selector? then $(selector) else $(@el).parent()
# Set Defaults
{
diff --git a/app/assets/javascripts/lib/datetime_utility.js.coffee b/app/assets/javascripts/lib/datetime_utility.js.coffee
new file mode 100644
index 00000000000..ad1d1c70481
--- /dev/null
+++ b/app/assets/javascripts/lib/datetime_utility.js.coffee
@@ -0,0 +1,17 @@
+((w) ->
+
+ w.gl ?= {}
+ w.gl.utils ?= {}
+
+ w.gl.utils.formatDate = (datetime) ->
+ dateFormat(datetime, 'mmm d, yyyy h:MMtt Z')
+
+ w.gl.utils.localTimeAgo = ($timeagoEls, setTimeago = true) ->
+ $timeagoEls.each( ->
+ $el = $(@)
+ $el.attr('title', gl.utils.formatDate($el.attr('datetime')))
+ )
+
+ $timeagoEls.timeago() if setTimeago
+
+) window
diff --git a/app/assets/javascripts/lib/notify.js.coffee b/app/assets/javascripts/lib/notify.js.coffee
index 3f9ca39912c..9e28353ac34 100644
--- a/app/assets/javascripts/lib/notify.js.coffee
+++ b/app/assets/javascripts/lib/notify.js.coffee
@@ -2,6 +2,11 @@
notificationGranted = (message, opts, onclick) ->
notification = new Notification(message, opts)
+ # Hide the notification after X amount of seconds
+ setTimeout ->
+ notification.close()
+ , 8000
+
if onclick
notification.onclick = onclick
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 9946249adbf..ef0b534a709 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -142,7 +142,7 @@ class @MergeRequestTabs
url: "#{source}.json"
success: (data) =>
document.querySelector("div#commits").innerHTML = data.html
- $('.js-timeago').timeago()
+ gl.utils.localTimeAgo($('.js-timeago', 'div#commits'))
@commitsLoaded = true
@scrollToElement("#commits")
@@ -153,7 +153,7 @@ class @MergeRequestTabs
url: "#{source}.json" + @_location.search
success: (data) =>
document.querySelector("div#diffs").innerHTML = data.html
- $('.js-timeago').timeago()
+ gl.utils.localTimeAgo($('.js-timeago', 'div#diffs'))
$('div#diffs .js-syntax-highlight').syntaxHighlight()
@expandViewContainer() if @diffViewType() is 'parallel'
@diffsLoaded = true
@@ -166,7 +166,7 @@ class @MergeRequestTabs
url: "#{source}.json"
success: (data) =>
document.querySelector("div#builds").innerHTML = data.html
- $('.js-timeago').timeago()
+ gl.utils.localTimeAgo($('.js-timeago', 'div#builds'))
@buildsLoaded = true
@scrollToElement("#builds")
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index 84a8887fbce..065626beeb8 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -12,10 +12,19 @@ class @MergeRequestWidget
@readyForCICheck = true
clearInterval @fetchBuildStatusInterval
+ @clearEventListeners()
+ @addEventListeners()
@pollCIStatus()
notifyPermissions()
- setOpts: (@opts) ->
+ clearEventListeners: ->
+ $(document).off 'page:change.merge_request'
+
+ addEventListeners: ->
+ $(document).on 'page:change.merge_request', =>
+ if $('body').data('page') isnt 'projects:merge_requests:show'
+ clearInterval @fetchBuildStatusInterval
+ @clearEventListeners()
mergeInProgress: (deleteSourceBranch = false)->
$.ajax
@@ -38,7 +47,7 @@ class @MergeRequestWidget
$('.mr-state-widget').replaceWith(data)
ciLabelForStatus: (status) ->
- if status == 'success'
+ if status is 'success'
'passed'
else
status
@@ -67,18 +76,28 @@ class @MergeRequestWidget
@opts.ci_status = data.status
return
- if data.status isnt @opts.ci_status
+ if data.status isnt @opts.ci_status and data.status?
@showCIStatus data.status
if data.coverage
@showCICoverage data.coverage
if showNotification
- message = @opts.ci_message.replace('{{status}}', @ciLabelForStatus(data.status))
+ status = @ciLabelForStatus(data.status)
+
+ if status is "preparing"
+ title = @opts.ci_title.preparing
+ status = status.charAt(0).toUpperCase() + status.slice(1);
+ message = @opts.ci_message.preparing.replace('{{status}}', status)
+ else
+ title = @opts.ci_title.normal
+ message = @opts.ci_message.normal.replace('{{status}}', status)
+
+ title = title.replace('{{status}}', status)
message = message.replace('{{sha}}', data.sha)
message = message.replace('{{title}}', data.title)
notify(
- "Build #{@ciLabelForStatus(data.status)}",
+ title,
message,
@opts.gitlab_icon,
->
@@ -98,6 +117,8 @@ class @MergeRequestWidget
@setMergeButtonClass('btn-danger')
when "running", "pending"
@setMergeButtonClass('btn-warning')
+ when "success"
+ @setMergeButtonClass('btn-create')
else
$('.ci_widget.ci-error').show()
@setMergeButtonClass('btn-danger')
@@ -107,4 +128,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
- $('.accept_merge_request').removeClass("btn-create").addClass(css_class)
+ $('.accept_merge_request')
+ .removeClass('btn-danger btn-warning btn-create')
+ .addClass(css_class)
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 86e3b860fcb..a67890200dd 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -163,9 +163,15 @@ class @Notes
else if @isNewNote(note)
@note_ids.push(note.id)
- $('ul.main-notes-list')
+ $notesList = $('ul.main-notes-list')
+
+ $notesList
.append(note.html)
.syntaxHighlight()
+
+ # Update datetime format on the recent note
+ gl.utils.localTimeAgo($notesList.find("#note_#{note.id} .js-timeago"), false)
+
@initTaskList()
@updateNotesCount(1)
@@ -217,6 +223,8 @@ class @Notes
# append new note to all matching discussions
discussionContainer.append note_html
+ gl.utils.localTimeAgo($('.js-timeago', note_html), false)
+
@updateNotesCount(1)
###
@@ -345,7 +353,9 @@ class @Notes
updateNote: (_xhr, note, _status) =>
# Convert returned HTML to a jQuery object so we can modify it further
$html = $(note.html)
- $('.js-timeago', $html).timeago()
+
+ gl.utils.localTimeAgo($('.js-timeago', $html))
+
$html.syntaxHighlight()
$html.find('.js-task-list-container').taskList('enable')
diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee
index ae87c6c4e40..f4a2562885d 100644
--- a/app/assets/javascripts/profile.js.coffee
+++ b/app/assets/javascripts/profile.js.coffee
@@ -18,8 +18,11 @@ class @Profile
$(this).find('.btn-save').enable()
$(this).find('.loading-gif').hide()
- $('.update-notifications').on 'ajax:complete', ->
- $(this).find('.btn-save').enable()
+ $('.update-notifications').on 'ajax:success', (e, data) ->
+ if data.saved
+ new Flash("Notification settings saved", "notice")
+ else
+ new Flash("Failed to save new settings", "alert")
@bindEvents()
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index 87d313ed67c..07be85a32a5 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -37,19 +37,20 @@ class @Project
$('.update-notification').on 'click', (e) ->
e.preventDefault()
notification_level = $(@).data 'notification-level'
- $('#notification_level').val(notification_level)
+ label = $(@).data 'notification-title'
+ $('#notification_setting_level').val(notification_level)
$('#notification-form').submit()
- label = null
- switch notification_level
- when 0 then label = ' Disabled '
- when 1 then label = ' Participating '
- when 2 then label = ' Watching '
- when 3 then label = ' Global '
- when 4 then label = ' On Mention '
$('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>")
$(@).parents('ul').find('li.active').removeClass 'active'
$(@).parent().addClass 'active'
+ $('#notification-form').on 'ajax:success', (e, data) ->
+ if data.saved
+ new Flash("Notification settings saved", "notice")
+ else
+ new Flash("Failed to save new settings", "alert")
+
+
@projectSelectDropdown()
projectSelectDropdown: ->
diff --git a/app/assets/javascripts/project_select.js.coffee b/app/assets/javascripts/project_select.js.coffee
index be8ab9b428d..704bd8dee53 100644
--- a/app/assets/javascripts/project_select.js.coffee
+++ b/app/assets/javascripts/project_select.js.coffee
@@ -1,5 +1,37 @@
class @ProjectSelect
constructor: ->
+ $('.js-projects-dropdown-toggle').each (i, dropdown) ->
+ $dropdown = $(dropdown)
+
+ $dropdown.glDropdown(
+ filterable: true
+ filterRemote: true
+ search:
+ fields: ['name_with_namespace']
+ data: (term, callback) ->
+ finalCallback = (projects) ->
+ callback projects
+
+ if @includeGroups
+ projectsCallback = (projects) ->
+ groupsCallback = (groups) ->
+ data = groups.concat(projects)
+ finalCallback(data)
+
+ Api.groups term, false, groupsCallback
+ else
+ projectsCallback = finalCallback
+
+ if @groupId
+ Api.groupProjects @groupId, term, projectsCallback
+ else
+ Api.projects term, @orderBy, projectsCallback
+ url: (project) ->
+ project.web_url
+ text: (project) ->
+ project.name_with_namespace
+ )
+
$('.ajax-project-select').each (i, select) ->
@groupId = $(select).data('group-id')
@includeGroups = $(select).data('include-groups')
diff --git a/app/assets/javascripts/todos.js.coffee b/app/assets/javascripts/todos.js.coffee
index 886da72e261..00d2b641723 100644
--- a/app/assets/javascripts/todos.js.coffee
+++ b/app/assets/javascripts/todos.js.coffee
@@ -59,6 +59,8 @@ class @Todos
goToTodoUrl: (e)->
todoLink = $(this).data('url')
+ return unless todoLink
+
if e.metaKey
e.preventDefault()
window.open(todoLink,'_blank')
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index b3397d16016..3f015427d07 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -69,6 +69,7 @@ header {
}
.header-content {
+ position: relative;
height: $header-height;
padding-right: 20px;
@@ -76,6 +77,10 @@ header {
padding-right: 0;
}
+ .dropdown-menu {
+ margin-top: -5px;
+ }
+
.title {
margin: 0;
font-size: 19px;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 94f5a12ff6a..192d53b048a 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -58,12 +58,12 @@
.nav-search {
display: inline-block;
- width: 50%;
+ width: 100%;
padding: 11px 0;
/* Small devices (phones, tablets, 768px and lower) */
- @media (max-width: $screen-sm-min) {
- width: 100%;
+ @media (min-width: $screen-sm-min) {
+ width: 50%;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 1ebbd9b0e57..0b6be86ce6a 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -28,6 +28,7 @@ $gl-link-color: #3084bb;
$gl-dark-link-color: #333;
$gl-placeholder-color: #8f8f8f;
$gl-icon-color: $gl-placeholder-color;
+$gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color;
$gl-header-color: $gl-title-color;
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index c66efe978cd..6fe57c737b3 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -41,8 +41,17 @@
word-wrap: break-word;
.md {
- color: #7f8fa4;
+ color: $gl-grayish-blue;
font-size: $gl-font-size;
+
+ .label {
+ color: $gl-text-color;
+ font-size: inherit;
+ }
+
+ iframe.twitter-share-button {
+ vertical-align: bottom;
+ }
}
pre {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 88c1b614c74..8b6f37f21b5 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -263,6 +263,12 @@
}
}
+ .dropdown-content {
+ a:hover {
+ color: inherit;
+ }
+ }
+
.dropdown-menu-toggle {
width: 100%;
padding-top: 6px;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index b79335eab91..4ef548ffbe7 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -142,6 +142,7 @@
overflow: hidden;
font-size: 90%;
margin: 0 3px;
+ word-break: break-all;
}
.mr-list {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 4d4d508396d..f4da17fadaa 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -71,12 +71,24 @@
border-color: $focus-border-color;
}
}
+
+ p {
+ code {
+ white-space: normal;
+ }
+
+ pre {
+ code {
+ white-space: pre;
+ }
+ }
+ }
}
}
.discussion-form {
padding: $gl-padding-top $gl-padding;
- background-color: #fff;
+ background-color: $white-light;
}
.note-edit-form {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 7295fe51121..e421a31549a 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -81,9 +81,15 @@ ul.notes {
@include md-typography;
// On diffs code should wrap nicely and not overflow
- pre {
+ p {
code {
- white-space: pre;
+ white-space: normal;
+ }
+
+ pre {
+ code {
+ white-space: pre;
+ }
}
}
@@ -112,6 +118,10 @@ ul.notes {
margin: 10px 0;
}
}
+
+ a {
+ word-break: break-all;
+ }
}
.note-header {
@@ -127,7 +137,7 @@ ul.notes {
margin-right: 10px;
}
.line_content {
- white-space: pre-wrap;
+ white-space: pre;
}
}
@@ -145,19 +155,27 @@ ul.notes {
background: $background-color;
color: $text-color;
}
+
&.notes_line2 {
text-align: center;
padding: 10px 0;
border-left: 1px solid #ddd !important;
}
+
&.notes_content {
- background-color: #fff;
+ background-color: $background-color;
border-width: 1px 0;
padding: 0;
vertical-align: top;
+ white-space: normal;
+
&.parallel {
border-width: 1px;
}
+
+ .notes {
+ background-color: $white-light;
+ }
}
}
}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index e83fa9e3d52..75f78569e3c 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -34,6 +34,11 @@
color: #7f8fa4;
font-size: $gl-font-size;
+ .label {
+ color: $gl-text-color;
+ font-size: inherit;
+ }
+
p {
color: #5c5d5e;
}
diff --git a/app/controllers/groups/notification_settings_controller.rb b/app/controllers/groups/notification_settings_controller.rb
new file mode 100644
index 00000000000..de13b16ccf2
--- /dev/null
+++ b/app/controllers/groups/notification_settings_controller.rb
@@ -0,0 +1,16 @@
+class Groups::NotificationSettingsController < Groups::ApplicationController
+ before_action :authenticate_user!
+
+ def update
+ notification_setting = current_user.notification_settings_for(group)
+ saved = notification_setting.update_attributes(notification_setting_params)
+
+ render json: { saved: saved }
+ end
+
+ private
+
+ def notification_setting_params
+ params.require(:notification_setting).permit(:level)
+ end
+end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index d28e96c3f18..df98f56a1cd 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -60,6 +60,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
continue_login_process
end
+ rescue Gitlab::OAuth::SignupDisabledError
+ handle_signup_error
end
def omniauth_error
@@ -92,16 +94,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
continue_login_process
end
rescue Gitlab::OAuth::SignupDisabledError
- label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
- message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
-
- if current_application_settings.signup_enabled?
- message << " Create a GitLab account first, and then connect it to your #{label} account."
- end
-
- flash[:notice] = message
-
- redirect_to new_user_session_path
+ handle_signup_error
end
def handle_service_ticket provider, ticket
@@ -122,6 +115,19 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
end
+ def handle_signup_error
+ label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
+ message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
+
+ if current_application_settings.signup_enabled?
+ message << " Create a GitLab account first, and then connect it to your #{label} account."
+ end
+
+ flash[:notice] = message
+
+ redirect_to new_user_session_path
+ end
+
def oauth
@oauth ||= request.env['omniauth.auth']
end
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 1fd1d6882df..18ee55c839a 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -1,39 +1,18 @@
class Profiles::NotificationsController < Profiles::ApplicationController
def show
@user = current_user
- @notification = current_user.notification
- @project_members = current_user.project_members
- @group_members = current_user.group_members
+ @group_notifications = current_user.notification_settings.for_groups
+ @project_notifications = current_user.notification_settings.for_projects
end
def update
- type = params[:notification_type]
-
- @saved = if type == 'global'
- current_user.update_attributes(user_params)
- elsif type == 'group'
- group_member = current_user.group_members.find(params[:notification_id])
- group_member.notification_level = params[:notification_level]
- group_member.save
- else
- project_member = current_user.project_members.find(params[:notification_id])
- project_member.notification_level = params[:notification_level]
- project_member.save
- end
-
- respond_to do |format|
- format.html do
- if @saved
- flash[:notice] = "Notification settings saved"
- else
- flash[:alert] = "Failed to save new settings"
- end
-
- redirect_back_or_default(default: profile_notifications_path)
- end
-
- format.js
+ if current_user.update_attributes(user_params)
+ flash[:notice] = "Notification settings saved"
+ else
+ flash[:alert] = "Failed to save new settings"
end
+
+ redirect_back_or_default(default: profile_notifications_path)
end
def user_params
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index ae613f5e093..3e0cfc6aa65 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -237,6 +237,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
+ status = "preparing" if status.nil?
+
response = {
title: merge_request.title,
sha: merge_request.last_commit_short_sha,
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 1b9dd568043..707a0d0e5c6 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -39,8 +39,7 @@ class Projects::NotesController < Projects::ApplicationController
def destroy
if note.editable?
- note.destroy
- note.reset_events_cache
+ Notes::DeleteService.new(project, current_user).execute(note)
end
respond_to do |format|
diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb
new file mode 100644
index 00000000000..7d81cc03c73
--- /dev/null
+++ b/app/controllers/projects/notification_settings_controller.rb
@@ -0,0 +1,16 @@
+class Projects::NotificationSettingsController < Projects::ApplicationController
+ before_action :authenticate_user!
+
+ def update
+ notification_setting = current_user.notification_settings_for(project)
+ saved = notification_setting.update_attributes(notification_setting_params)
+
+ render json: { saved: saved }
+ end
+
+ private
+
+ def notification_setting_params
+ params.require(:notification_setting).permit(:level)
+ end
+end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 3cc37e59855..3768efe142a 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -101,14 +101,18 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format|
format.html do
+ if current_user
+ @membership = @project.team.find_member(current_user.id)
+
+ if @membership
+ @notification_setting = current_user.notification_settings_for(@project)
+ end
+ end
+
if @project.repository_exists?
if @project.empty_repo?
render 'projects/empty'
else
- if current_user
- @membership = @project.team.find_member(current_user.id)
- end
-
render :show
end
else
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e6ceb213532..16e5b8ac223 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -184,7 +184,7 @@ module ApplicationHelper
element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago #{"js-timeago-pending" unless skip_js}",
datetime: time.to_time.getutc.iso8601,
- title: time.in_time_zone.to_s(:medium),
+ title: time.to_time.in_time_zone.to_s(:medium),
data: { toggle: 'tooltip', placement: placement, container: 'body' }
unless skip_js
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index faba418c4db..94c6b548ecd 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -3,8 +3,16 @@ module NamespacesHelper
groups = current_user.owned_groups + current_user.masters_groups
users = [current_user.namespace]
- group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [display_path ? g.path : g.human_name, g.id]} ]
- users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [display_path ? u.path : u.human_name, u.id]} ]
+ data_attr_group = { 'data-options-parent' => 'groups' }
+ data_attr_users = { 'data-options-parent' => 'users' }
+
+ group_opts = [
+ "Groups", groups.sort_by(&:human_name).map { |g| [display_path ? g.path : g.human_name, g.id, data_attr_group] }
+ ]
+
+ users_opts = [
+ "Users", users.sort_by(&:human_name).map { |u| [display_path ? u.path : u.human_name, u.id, data_attr_users] }
+ ]
options = []
options << group_opts
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index 499c655d2bf..54ab9179efc 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -1,48 +1,48 @@
module NotificationsHelper
include IconsHelper
- def notification_icon(notification)
- if notification.disabled?
- icon('volume-off', class: 'ns-mute')
- elsif notification.participating?
- icon('volume-down', class: 'ns-part')
- elsif notification.watch?
- icon('volume-up', class: 'ns-watch')
- else
- icon('circle-o', class: 'ns-default')
+ def notification_icon_class(level)
+ case level.to_sym
+ when :disabled
+ 'microphone-slash'
+ when :participating
+ 'volume-up'
+ when :watch
+ 'eye'
+ when :mention
+ 'at'
+ when :global
+ 'globe'
end
end
- def notification_list_item(notification_level, user_membership)
- case notification_level
- when Notification::N_DISABLED
- update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash')
- when Notification::N_PARTICIPATING
- update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up')
- when Notification::N_WATCH
- update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye')
- when Notification::N_MENTION
- update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at')
- when Notification::N_GLOBAL
- update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe')
- else
- # do nothing
- end
+ def notification_icon(level, text = nil)
+ icon("#{notification_icon_class(level)} fw", text: text)
end
- def update_notification_link(notification_level, user_membership, title, icon)
- content_tag(:li, class: active_level_for(user_membership, notification_level)) do
- link_to '#', class: 'update-notification', data: { notification_level: notification_level } do
- icon("#{icon} fw", text: title)
- end
+ def notification_title(level)
+ case level.to_sym
+ when :participating
+ 'Participate'
+ when :mention
+ 'On mention'
+ else
+ level.to_s.titlecase
end
end
- def notification_label(user_membership)
- Notification.new(user_membership).to_s
- end
+ def notification_list_item(level, setting)
+ title = notification_title(level)
+
+ data = {
+ notification_level: level,
+ notification_title: title
+ }
- def active_level_for(user_membership, level)
- 'active' if user_membership.notification_level == level
+ content_tag(:li, class: ('active' if setting.level == level)) do
+ link_to '#', class: 'update-notification', data: data do
+ notification_icon(level, title)
+ end
+ end
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 4e4c6e301d5..7e00aacceaa 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -65,21 +65,14 @@ module ProjectsHelper
link_to(simple_sanitize(owner.name), user_path(owner))
end
- project_link = link_to project_path(project), { class: "project-item-select-holder" } do
- link_output = simple_sanitize(project.name)
+ project_link = link_to simple_sanitize(project.name), project_path(project), { class: "project-item-select-holder" }
- if current_user
- link_output += project_select_tag :project_path,
- class: "project-item-select js-projects-dropdown",
- data: { include_groups: false, order_by: 'last_activity_at' }
- end
-
- link_output
+ if current_user
+ project_link << icon("chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle", data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" })
end
- project_link += icon "chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle" if current_user
- full_title = namespace_link + ' / ' + project_link
- full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url) if name
+ full_title = "#{namespace_link} / #{project_link}".html_safe
+ full_title << ' &middot; '.html_safe << link_to(simple_sanitize(name), url) if name
full_title
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index edc5686cf08..2f066682180 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -20,6 +20,8 @@ module TodosHelper
end
def todo_target_path(todo)
+ return unless todo.target.present?
+
anchor = dom_id(todo.note) if todo.note.present?
if todo.for_commit?
diff --git a/app/models/commit.rb b/app/models/commit.rb
index d09876a07d9..11ecfcace14 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -150,13 +150,11 @@ class Commit
end
def hook_attrs(with_changed_files: false)
- path_with_namespace = project.path_with_namespace
-
data = {
id: id,
message: safe_message,
timestamp: committed_date.xmlschema,
- url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{id}",
+ url: commit_url,
author: {
name: author_name,
email: author_email
@@ -170,6 +168,10 @@ class Commit
data
end
+ def commit_url
+ project.present? ? "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{id}" : ""
+ end
+
# Discover issues should be closed when this commit is pushed to a project's
# default branch.
def closes_issues(current_user = self.committer)
diff --git a/app/models/concerns/notifiable.rb b/app/models/concerns/notifiable.rb
deleted file mode 100644
index d7dcd97911d..00000000000
--- a/app/models/concerns/notifiable.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# == Notifiable concern
-#
-# Contains notification functionality
-#
-module Notifiable
- extend ActiveSupport::Concern
-
- included do
- validates :notification_level, inclusion: { in: Notification.project_notification_levels }, presence: true
- end
-
- def notification
- @notification ||= Notification.new(self)
- end
-end
diff --git a/app/models/group.rb b/app/models/group.rb
index b332601c59b..9a04ac70d35 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -27,6 +27,7 @@ class Group < Namespace
has_many :users, through: :group_members
has_many :project_group_links, dependent: :destroy
has_many :shared_projects, through: :project_group_links, source: :project
+ has_many :notification_settings, dependent: :destroy, as: :source
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :visibility_level_allowed_by_projects
diff --git a/app/models/member.rb b/app/models/member.rb
index ca08007b7eb..60efafef211 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -19,7 +19,6 @@
class Member < ActiveRecord::Base
include Sortable
- include Notifiable
include Gitlab::Access
attr_accessor :raw_invite_token
@@ -56,12 +55,15 @@ class Member < ActiveRecord::Base
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
after_create :send_invite, if: :invite?
+ after_create :create_notification_setting, unless: :invite?
after_create :post_create_hook, unless: :invite?
after_update :post_update_hook, unless: :invite?
after_destroy :post_destroy_hook, unless: :invite?
delegate :name, :username, :email, to: :user, prefix: true
+ default_value_for :notification_level, NotificationSetting.levels[:global]
+
class << self
def find_by_invite_token(invite_token)
invite_token = Devise.token_generator.digest(self, :invite_token, invite_token)
@@ -160,6 +162,14 @@ class Member < ActiveRecord::Base
send_invite
end
+ def create_notification_setting
+ user.notification_settings.find_or_create_for(source)
+ end
+
+ def notification_setting
+ @notification_setting ||= user.notification_settings_for(source)
+ end
+
private
def send_invite
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index 65d2ea00570..9fb474a1a93 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -24,7 +24,6 @@ class GroupMember < Member
# Make sure group member points only to group as it source
default_value_for :source_type, SOURCE_TYPE
- default_value_for :notification_level, Notification::N_GLOBAL
validates_format_of :source_type, with: /\ANamespace\z/
default_scope { where(source_type: SOURCE_TYPE) }
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 560d1690e14..07ddb02ae9d 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -27,7 +27,6 @@ class ProjectMember < Member
# Make sure project member points only to project as it source
default_value_for :source_type, SOURCE_TYPE
- default_value_for :notification_level, Notification::N_GLOBAL
validates_format_of :source_type, with: /\AProject\z/
default_scope { where(source_type: SOURCE_TYPE) }
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index bf185cb5dd8..e410febdfff 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -128,7 +128,7 @@ class MergeRequest < ActiveRecord::Base
validates :target_project, presence: true
validates :target_branch, presence: true
validates :merge_user, presence: true, if: :merge_when_build_succeeds?
- validate :validate_branches
+ validate :validate_branches, unless: :allow_broken
validate :validate_fork
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
@@ -218,7 +218,7 @@ class MergeRequest < ActiveRecord::Base
end
if opened? || reopened?
- similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.id).opened
+ similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.try(:id)).opened
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any?
errors.add :validate_branches,
@@ -345,7 +345,7 @@ class MergeRequest < ActiveRecord::Base
def hook_attrs
attrs = {
- source: source_project.hook_attrs,
+ source: source_project.try(:hook_attrs),
target: target_project.hook_attrs,
last_commit: nil,
work_in_progress: work_in_progress?
diff --git a/app/models/notification.rb b/app/models/notification.rb
deleted file mode 100644
index 171b8df45c2..00000000000
--- a/app/models/notification.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-class Notification
- #
- # Notification levels
- #
- N_DISABLED = 0
- N_PARTICIPATING = 1
- N_WATCH = 2
- N_GLOBAL = 3
- N_MENTION = 4
-
- attr_accessor :target
-
- class << self
- def notification_levels
- [N_DISABLED, N_MENTION, N_PARTICIPATING, N_WATCH]
- end
-
- def options_with_labels
- {
- disabled: N_DISABLED,
- participating: N_PARTICIPATING,
- watch: N_WATCH,
- mention: N_MENTION,
- global: N_GLOBAL
- }
- end
-
- def project_notification_levels
- [N_DISABLED, N_MENTION, N_PARTICIPATING, N_WATCH, N_GLOBAL]
- end
- end
-
- def initialize(target)
- @target = target
- end
-
- def disabled?
- target.notification_level == N_DISABLED
- end
-
- def participating?
- target.notification_level == N_PARTICIPATING
- end
-
- def watch?
- target.notification_level == N_WATCH
- end
-
- def global?
- target.notification_level == N_GLOBAL
- end
-
- def mention?
- target.notification_level == N_MENTION
- end
-
- def level
- target.notification_level
- end
-
- def to_s
- case level
- when N_DISABLED
- 'Disabled'
- when N_PARTICIPATING
- 'Participating'
- when N_WATCH
- 'Watching'
- when N_MENTION
- 'On mention'
- when N_GLOBAL
- 'Global'
- else
- # do nothing
- end
- end
-end
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
new file mode 100644
index 00000000000..5001738f411
--- /dev/null
+++ b/app/models/notification_setting.rb
@@ -0,0 +1,28 @@
+class NotificationSetting < ActiveRecord::Base
+ enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 }
+
+ default_value_for :level, NotificationSetting.levels[:global]
+
+ belongs_to :user
+ belongs_to :source, polymorphic: true
+
+ validates :user, presence: true
+ validates :source, presence: true
+ validates :level, presence: true
+ validates :user_id, uniqueness: { scope: [:source_type, :source_id],
+ message: "already exists in source",
+ allow_nil: true }
+
+ scope :for_groups, -> { where(source_type: 'Namespace') }
+ scope :for_projects, -> { where(source_type: 'Project') }
+
+ def self.find_or_create_for(source)
+ setting = find_or_initialize_by(source: source)
+
+ unless setting.persisted?
+ setting.save
+ end
+
+ setting
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 3e1f04b4158..fadc8bb2c9e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -154,6 +154,7 @@ class Project < ActiveRecord::Base
has_many :project_group_links, dependent: :destroy
has_many :invited_groups, through: :project_group_links, source: :group
has_many :todos, dependent: :destroy
+ has_many :notification_settings, dependent: :destroy, as: :source
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
@@ -388,9 +389,15 @@ class Project < ActiveRecord::Base
def add_import_job
if forked?
- RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
+ job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
else
- RepositoryImportWorker.perform_async(self.id)
+ job_id = RepositoryImportWorker.perform_async(self.id)
+ end
+
+ if job_id
+ Rails.logger.info "Import job started for #{path_with_namespace} with job ID #{job_id}"
+ else
+ Rails.logger.error "Import job failed to start for #{path_with_namespace}"
end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 8dead3a5884..0b2289cfa39 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -253,6 +253,8 @@ class Repository
# This ensures this particular cache is flushed after the first commit to a
# new repository.
expire_emptiness_caches if empty?
+ expire_branch_count_cache
+ expire_tag_count_cache
end
def expire_branch_cache(branch_name = nil)
@@ -896,9 +898,9 @@ class Repository
end
def main_language
- unless empty?
- Linguist::Repository.new(rugged, rugged.head.target_id).language
- end
+ return if empty? || rugged.head_unborn?
+
+ Linguist::Repository.new(rugged, rugged.head.target_id).language
end
def avatar
diff --git a/app/models/user.rb b/app/models/user.rb
index 2b0bee2099f..031315debd7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -143,6 +143,7 @@ class User < ActiveRecord::Base
has_many :spam_logs, dependent: :destroy
has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :todos, dependent: :destroy
+ has_many :notification_settings, dependent: :destroy
#
# Validations
@@ -157,7 +158,7 @@ class User < ActiveRecord::Base
presence: true,
uniqueness: { case_sensitive: false }
- validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
+ validates :notification_level, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? }
@@ -190,6 +191,13 @@ class User < ActiveRecord::Base
# Note: When adding an option, it MUST go on the end of the array.
enum project_view: [:readme, :activity, :files]
+ # Notification level
+ # Note: When adding an option, it MUST go on the end of the array.
+ #
+ # TODO: Add '_prefix: :notification' to enum when update to Rails 5. https://github.com/rails/rails/pull/19813
+ # Because user.notification_disabled? is much better than user.disabled?
+ enum notification_level: [:disabled, :participating, :watch, :global, :mention]
+
alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true
@@ -349,10 +357,6 @@ class User < ActiveRecord::Base
"#{self.class.reference_prefix}#{username}"
end
- def notification
- @notification ||= Notification.new(self)
- end
-
def generate_password
if self.force_random_password
self.password = self.password_confirmation = Devise.friendly_token.first(8)
@@ -827,6 +831,10 @@ class User < ActiveRecord::Base
end
end
+ def notification_settings_for(source)
+ notification_settings.find_or_initialize_by(source: source)
+ end
+
private
def projects_union
diff --git a/app/services/notes/delete_service.rb b/app/services/notes/delete_service.rb
new file mode 100644
index 00000000000..7f1b30ec84e
--- /dev/null
+++ b/app/services/notes/delete_service.rb
@@ -0,0 +1,8 @@
+module Notes
+ class DeleteService < BaseService
+ def execute(note)
+ note.destroy
+ note.reset_events_cache
+ end
+ end
+end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index eff0d96f93d..42ec1ac9e1a 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -253,8 +253,8 @@ class NotificationService
def project_watchers(project)
project_members = project_member_notification(project)
- users_with_project_level_global = project_member_notification(project, Notification::N_GLOBAL)
- users_with_group_level_global = group_member_notification(project, Notification::N_GLOBAL)
+ users_with_project_level_global = project_member_notification(project, :global)
+ users_with_group_level_global = group_member_notification(project, :global)
users = users_with_global_level_watch([users_with_project_level_global, users_with_group_level_global].flatten.uniq)
users_with_project_setting = select_project_member_setting(project, users_with_project_level_global, users)
@@ -264,18 +264,16 @@ class NotificationService
end
def project_member_notification(project, notification_level=nil)
- project_members = project.project_members
-
if notification_level
- project_members.where(notification_level: notification_level).pluck(:user_id)
+ project.notification_settings.where(level: NotificationSetting.levels[notification_level]).pluck(:user_id)
else
- project_members.pluck(:user_id)
+ project.notification_settings.pluck(:user_id)
end
end
def group_member_notification(project, notification_level)
if project.group
- project.group.group_members.where(notification_level: notification_level).pluck(:user_id)
+ project.group.notification_settings.where(level: NotificationSetting.levels[notification_level]).pluck(:user_id)
else
[]
end
@@ -284,13 +282,13 @@ class NotificationService
def users_with_global_level_watch(ids)
User.where(
id: ids,
- notification_level: Notification::N_WATCH
+ notification_level: NotificationSetting.levels[:watch]
).pluck(:id)
end
# Build a list of users based on project notifcation settings
def select_project_member_setting(project, global_setting, users_global_level_watch)
- users = project_member_notification(project, Notification::N_WATCH)
+ users = project_member_notification(project, :watch)
# If project setting is global, add to watch list if global setting is watch
global_setting.each do |user_id|
@@ -304,7 +302,7 @@ class NotificationService
# Build a list of users based on group notification settings
def select_group_member_setting(project, project_members, global_setting, users_global_level_watch)
- uids = group_member_notification(project, Notification::N_WATCH)
+ uids = group_member_notification(project, :watch)
# Group setting is watch, add to users list if user is not project member
users = []
@@ -331,40 +329,46 @@ class NotificationService
# Remove users with disabled notifications from array
# Also remove duplications and nil recipients
def reject_muted_users(users, project = nil)
- reject_users(users, :disabled?, project)
+ reject_users(users, :disabled, project)
end
# Remove users with notification level 'Mentioned'
def reject_mention_users(users, project = nil)
- reject_users(users, :mention?, project)
+ reject_users(users, :mention, project)
end
- # Reject users which method_name from notification object returns true.
+ # Reject users which has certain notification level
#
# Example:
- # reject_users(users, :watch?, project)
+ # reject_users(users, :watch, project)
#
- def reject_users(users, method_name, project = nil)
+ def reject_users(users, level, project = nil)
+ level = level.to_s
+
+ unless NotificationSetting.levels.keys.include?(level)
+ raise 'Invalid notification level'
+ end
+
users = users.to_a.compact.uniq
users = users.reject(&:blocked?)
users.reject do |user|
- next user.notification.send(method_name) unless project
+ next user.notification_level == level unless project
- member = project.project_members.find_by(user_id: user.id)
+ setting = user.notification_settings_for(project)
- if !member && project.group
- member = project.group.group_members.find_by(user_id: user.id)
+ if !setting && project.group
+ setting = user.notification_settings_for(project.group)
end
- # reject users who globally set mention notification and has no membership
- next user.notification.send(method_name) unless member
+ # reject users who globally set mention notification and has no setting per project/group
+ next user.notification_level == level unless setting
# reject users who set mention notification in project
- next true if member.notification.send(method_name)
+ next true if setting.level == level
- # reject users who have N_MENTION in project and disabled in global settings
- member.notification.global? && user.notification.send(method_name)
+ # reject users who have mention level in project and disabled in global settings
+ setting.global? && user.notification_level == level
end
end
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 0f3b8119379..44339293095 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -45,6 +45,8 @@
%h1.title= title
+ = yield :header_content
+
= render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index a7ef31acd3d..6dfe7fbdae8 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -17,4 +17,12 @@
- content_for :scripts_body do
= render "layouts/init_auto_complete" if current_user
+- content_for :header_content do
+ .js-dropdown-menu-projects
+ .dropdown-menu.dropdown-select.dropdown-menu-projects
+ = dropdown_title("Go to a project")
+ = dropdown_filter("Search your projects")
+ = dropdown_content
+ = dropdown_loading
+
= render template: "layouts/application"
diff --git a/app/views/profiles/notifications/_group_settings.html.haml b/app/views/profiles/notifications/_group_settings.html.haml
new file mode 100644
index 00000000000..89ae7ffda2b
--- /dev/null
+++ b/app/views/profiles/notifications/_group_settings.html.haml
@@ -0,0 +1,13 @@
+%li.notification-list-item
+ %span.notification.fa.fa-holder.append-right-5
+ - if setting.global?
+ = notification_icon(current_user.notification_level)
+ - else
+ = notification_icon(setting.level)
+
+ %span.str-truncated
+ = link_to group.name, group_path(group)
+
+ .pull-right
+ = form_for [group, setting], remote: true, html: { class: 'update-notifications' } do |f|
+ = f.select :level, NotificationSetting.levels.keys, {}, class: 'form-control trigger-submit'
diff --git a/app/views/profiles/notifications/_project_settings.html.haml b/app/views/profiles/notifications/_project_settings.html.haml
new file mode 100644
index 00000000000..17c097154da
--- /dev/null
+++ b/app/views/profiles/notifications/_project_settings.html.haml
@@ -0,0 +1,13 @@
+%li.notification-list-item
+ %span.notification.fa.fa-holder.append-right-5
+ - if setting.global?
+ = notification_icon(current_user.notification_level)
+ - else
+ = notification_icon(setting.level)
+
+ %span.str-truncated
+ = link_to_project(project)
+
+ .pull-right
+ = form_for [project.namespace.becomes(Namespace), project, setting], remote: true, html: { class: 'update-notifications' } do |f|
+ = f.select :level, NotificationSetting.levels.keys, {}, class: 'form-control trigger-submit'
diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml
deleted file mode 100644
index d0d044136f6..00000000000
--- a/app/views/profiles/notifications/_settings.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-%li.notification-list-item
- %span.notification.fa.fa-holder.append-right-5
- - if notification.global?
- = notification_icon(@notification)
- - else
- = notification_icon(notification)
-
- %span.str-truncated
- - if membership.kind_of? GroupMember
- = link_to membership.group.name, membership.group
- - else
- = link_to_project(membership.project)
- .pull-right
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
- = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
- = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
- = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'form-control trigger-submit'
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 6609295a2a5..a2a505c082b 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -1,8 +1,12 @@
- page_title "Notifications"
- header_title page_title, profile_notifications_path
-= form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f|
- = form_errors(@user)
+%div
+ - if @user.errors.any?
+ %div.alert.alert-danger
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
= hidden_field_tag :notification_type, 'global'
.row
@@ -16,56 +20,55 @@
.col-lg-9
%h5
Global notification settings
- .form-group
- = f.label :notification_email, class: "label-light"
- = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2"
- .form-group
- = f.label :notification_level, class: 'label-light'
- .radio
- = f.label :notification_level, value: Notification::N_DISABLED do
- = f.radio_button :notification_level, Notification::N_DISABLED
- .level-title
- Disabled
- %p You will not get any notifications via email
- .radio
- = f.label :notification_level, value: Notification::N_MENTION do
- = f.radio_button :notification_level, Notification::N_MENTION
- .level-title
- On Mention
- %p You will receive notifications only for comments in which you were @mentioned
+ = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f|
+ .form-group
+ = f.label :notification_email, class: "label-light"
+ = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2"
+ .form-group
+ = f.label :notification_level, class: 'label-light'
+ .radio
+ = f.label :notification_level, value: :disabled do
+ = f.radio_button :notification_level, :disabled
+ .level-title
+ Disabled
+ %p You will not get any notifications via email
- .radio
- = f.label :notification_level, value: Notification::N_PARTICIPATING do
- = f.radio_button :notification_level, Notification::N_PARTICIPATING
- .level-title
- Participating
- %p You will only receive notifications from related resources (e.g. from your commits or assigned issues)
+ .radio
+ = f.label :notification_level, value: :mention do
+ = f.radio_button :notification_level, :mention
+ .level-title
+ On Mention
+ %p You will receive notifications only for comments in which you were @mentioned
- .radio
- = f.label :notification_level, value: Notification::N_WATCH do
- = f.radio_button :notification_level, Notification::N_WATCH
- .level-title
- Watch
- %p You will receive notifications for any activity
+ .radio
+ = f.label :notification_level, value: :participating do
+ = f.radio_button :notification_level, :participating
+ .level-title
+ Participating
+ %p You will only receive notifications from related resources (e.g. from your commits or assigned issues)
- .prepend-top-default
- = f.submit 'Update settings', class: "btn btn-create"
+ .radio
+ = f.label :notification_level, value: :watch do
+ = f.radio_button :notification_level, :watch
+ .level-title
+ Watch
+ %p You will receive notifications for any activity
+
+ .prepend-top-default
+ = f.submit 'Update settings', class: "btn btn-create"
%hr
-.col-lg-9.col-lg-push-3
- %h5
- Groups (#{@group_members.count})
- %div
- %ul.bordered-list
- - @group_members.each do |group_member|
- - notification = Notification.new(group_member)
- = render 'settings', type: 'group', membership: group_member, notification: notification
- %h5
- Projects (#{@project_members.count})
- %p.account-well
- To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group.
- .append-bottom-default
- %ul.bordered-list
- - @project_members.each do |project_member|
- - notification = Notification.new(project_member)
- = render 'settings', type: 'project', membership: project_member, notification: notification
+ %h5
+ Groups (#{@group_notifications.count})
+ %div
+ %ul.bordered-list
+ - @group_notifications.each do |setting|
+ = render 'group_settings', setting: setting, group: setting.source
+ %h5
+ Projects (#{@project_notifications.count})
+ %p.account-well
+ To specify the notification level per project of a group you belong to, you need to visit project page and change notification level there.
+ .append-bottom-default
+ %ul.bordered-list
+ - @project_notifications.each do |setting|
+ = render 'project_settings', setting: setting, project: setting.source
diff --git a/app/views/profiles/notifications/update.js.haml b/app/views/profiles/notifications/update.js.haml
deleted file mode 100644
index 84c6ab25599..00000000000
--- a/app/views/profiles/notifications/update.js.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- if @saved
- :plain
- new Flash("Notification settings saved", "notice")
-- else
- :plain
- new Flash("Failed to save new settings", "alert")
diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml
index a3786c35a1f..c1e3e5b73a2 100644
--- a/app/views/projects/buttons/_notifications.html.haml
+++ b/app/views/projects/buttons/_notifications.html.haml
@@ -1,20 +1,11 @@
-- case @membership
-- when ProjectMember
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do
- = hidden_field_tag :notification_type, 'project'
- = hidden_field_tag :notification_id, @membership.id
- = hidden_field_tag :notification_level
+- if @notification_setting
+ = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
+ = f.hidden_field :level
%span.dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
= icon('bell')
- = notification_label(@membership)
+ = notification_title(@notification_setting.level)
= icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- - Notification.project_notification_levels.each do |level|
- = notification_list_item(level, @membership)
-
-- when GroupMember
- .btn.disabled.notifications-btn.has-tooltip{title: "To change the notification level, you need to be a member of the project itself, not only its group."}
- = icon('bell')
- = notification_label(@membership)
- = icon('angle-down')
+ - NotificationSetting.levels.each do |level|
+ = notification_list_item(level.first, @notification_setting)
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index 3e4ab09c6d4..1e6724fc92b 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form js-requires-input' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form js-requires-input js-quick-submit' } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request
:javascript
diff --git a/app/views/projects/merge_requests/widget/_show.html.haml b/app/views/projects/merge_requests/widget/_show.html.haml
index 92d95358937..3c68d61c4b5 100644
--- a/app/views/projects/merge_requests/widget/_show.html.haml
+++ b/app/views/projects/merge_requests/widget/_show.html.haml
@@ -8,20 +8,22 @@
= render 'projects/merge_requests/widget/locked'
:javascript
- var merge_request_widget;
var opts = {
merge_check_url: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
ci_status_url: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "",
- ci_message: "Build {{status}} for \"{{title}}\"",
+ ci_message: {
+ normal: "Build {{status}} for \"{{title}}\"",
+ preparing: "{{status}} build for \"{{title}}\""
+ },
ci_enable: #{@project.ci_service ? "true" : "false"},
+ ci_title: {
+ preparing: "{{status}} build",
+ normal: "Build {{status}}"
+ },
builds_path: "#{builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}"
};
- if(typeof merge_request_widget === 'undefined') {
- merge_request_widget = new MergeRequestWidget(opts);
- } else {
- merge_request_widget.setOpts(opts);
- }
+ merge_request_widget = new MergeRequestWidget(opts);
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 25233112132..a4c6094c69a 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -19,7 +19,7 @@
- if current_user.can_select_namespace?
.input-group-addon
= root_url
- = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2', tabindex: 1}
+ = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1}
.input-group-addon
\/
- else
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 5c42423541e..03a44ca99c0 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -10,12 +10,12 @@
= "#{note.author.to_reference} commented"
%a{ href: "##{dom_id(note)}" }
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago')
- - if note_editable?(note)
- .note-actions
- - access = note.project.team.human_max_access(note.author.id)
- - if access
- %span.note-role
- = access
+ .note-actions
+ - access = note.project.team.human_max_access(note.author.id)
+ - if access
+ %span.note-role
+ = access
+ - if note_editable?(note)
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do
= icon('pencil')
= link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger' do
diff --git a/app/views/shared/_commit_message_container.html.haml b/app/views/shared/_commit_message_container.html.haml
index 7afbaeddee8..0a38327baa2 100644
--- a/app/views/shared/_commit_message_container.html.haml
+++ b/app/views/shared/_commit_message_container.html.haml
@@ -6,7 +6,7 @@
.commit-message-container
.max-width-marker
= text_area_tag 'commit_message',
- (params[:commit_message] || local_assigns[:text]),
+ (params[:commit_message] || local_assigns[:text] || local_assigns[:placeholder]),
class: 'form-control js-commit-message', placeholder: local_assigns[:placeholder],
required: true, rows: (local_assigns[:rows] || 3),
id: "commit_message-#{nonce}"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 35c7c425a5a..56caee47c97 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -46,6 +46,15 @@ production: &base
#
# relative_url_root: /gitlab
+ # Trusted Proxies
+ # Customize if you have GitLab behind a reverse proxy which is running on a different machine.
+ # Add the IP address for your reverse proxy to the list, otherwise users will appear signed in from that address.
+ trusted_proxies:
+ # Examples:
+ #- 192.168.1.0/24
+ #- 192.168.2.1
+ #- 2001:0db8::/32
+
# Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
# user: git
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 72c4d8d61ce..2167da306f2 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -190,6 +190,7 @@ Settings.gitlab.default_projects_features['visibility_level'] = Settings.send
Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive') if Settings.gitlab['repository_downloads_path'].nil?
Settings.gitlab['restricted_signup_domains'] ||= []
Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
+Settings.gitlab['trusted_proxies'] ||= []
#
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index 1b445bbbd10..22fe51a4534 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -1,4 +1,5 @@
if Gitlab::Metrics.enabled?
+ require 'pathname'
require 'influxdb'
require 'connection_pool'
require 'method_source'
@@ -85,9 +86,6 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(const)
end
- config.instrument_methods(Banzai::ReferenceExtractor)
- config.instrument_instance_methods(Banzai::ReferenceExtractor)
-
config.instrument_methods(Banzai::Renderer)
config.instrument_methods(Banzai::Querying)
@@ -98,6 +96,17 @@ if Gitlab::Metrics.enabled?
config.instrument_methods(Gitlab::ReferenceExtractor)
config.instrument_instance_methods(Gitlab::ReferenceExtractor)
+
+ # Instrument all service classes
+ services = Rails.root.join('app', 'services')
+
+ Dir[services.join('**', '*.rb')].each do |file_path|
+ path = Pathname.new(file_path).relative_path_from(services)
+ const = path.to_s.sub('.rb', '').camelize.constantize
+
+ config.instrument_methods(const)
+ config.instrument_instance_methods(const)
+ end
end
GC::Profiler.enable
diff --git a/config/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb
new file mode 100644
index 00000000000..b8cc025bae2
--- /dev/null
+++ b/config/initializers/trusted_proxies.rb
@@ -0,0 +1,2 @@
+Rails.application.config.action_dispatch.trusted_proxies =
+ [ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies)
diff --git a/config/routes.rb b/config/routes.rb
index 842fbb99843..48601b7567b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -406,6 +406,7 @@ Rails.application.routes.draw do
resource :avatar, only: [:destroy]
resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :update, :new, :create]
+ resource :notification_setting, only: [:update]
end
end
@@ -607,6 +608,7 @@ Rails.application.routes.draw do
resources :forks, only: [:index, :new, :create]
resource :import, only: [:new, :create, :show]
+ resource :notification_setting, only: [:update]
resources :refs, only: [] do
collection do
diff --git a/db/migrate/20160328112808_create_notification_settings.rb b/db/migrate/20160328112808_create_notification_settings.rb
new file mode 100644
index 00000000000..4755da8b806
--- /dev/null
+++ b/db/migrate/20160328112808_create_notification_settings.rb
@@ -0,0 +1,11 @@
+class CreateNotificationSettings < ActiveRecord::Migration
+ def change
+ create_table :notification_settings do |t|
+ t.references :user, null: false
+ t.references :source, polymorphic: true, null: false
+ t.integer :level, default: 0, null: false
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb
new file mode 100644
index 00000000000..0a110869027
--- /dev/null
+++ b/db/migrate/20160328115649_migrate_new_notification_setting.rb
@@ -0,0 +1,17 @@
+# This migration will create one row of NotificationSetting for each Member row
+# It can take long time on big instances.
+#
+# This migration can be done online but with following effects:
+# - during migration some users will receive notifications based on their global settings (project/group settings will be ignored)
+# - its possible to get duplicate records for notification settings since we don't create uniq index yet
+#
+class MigrateNewNotificationSetting < ActiveRecord::Migration
+ def up
+ timestamp = Time.now
+ execute "INSERT INTO notification_settings ( user_id, source_id, source_type, level, created_at, updated_at ) SELECT user_id, source_id, source_type, notification_level, '#{timestamp}', '#{timestamp}' FROM members WHERE user_id IS NOT NULL"
+ end
+
+ def down
+ execute "DELETE FROM notification_settings"
+ end
+end
diff --git a/db/migrate/20160328121138_add_notification_setting_index.rb b/db/migrate/20160328121138_add_notification_setting_index.rb
new file mode 100644
index 00000000000..8aebce0244d
--- /dev/null
+++ b/db/migrate/20160328121138_add_notification_setting_index.rb
@@ -0,0 +1,6 @@
+class AddNotificationSettingIndex < ActiveRecord::Migration
+ def change
+ add_index :notification_settings, :user_id
+ add_index :notification_settings, [:source_id, :source_type]
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index ec235c19131..44482de467e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -637,6 +637,18 @@ ActiveRecord::Schema.define(version: 20160331223143) do
add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree
add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree
+ create_table "notification_settings", force: :cascade do |t|
+ t.integer "user_id", null: false
+ t.integer "source_id", null: false
+ t.string "source_type", null: false
+ t.integer "level", default: 0, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
+ add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree
+
create_table "oauth_access_grants", force: :cascade do |t|
t.integer "resource_owner_id", null: false
t.integer "application_id", null: false
diff --git a/doc/README.md b/doc/README.md
index 724c7cca0f1..d2660930653 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -3,7 +3,7 @@
## User documentation
- [API](api/README.md) Automate GitLab via a simple and powerful API.
-- [CI](ci/README.md) GitLab Continuous Integration (CI) getting started, .gitlab-ci.yml options, and examples.
+- [CI](ci/README.md) GitLab Continuous Integration (CI) getting started, `.gitlab-ci.yml` options, and examples.
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
- [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).
diff --git a/doc/api/groups.md b/doc/api/groups.md
index d1b5c9f5f04..2821bc21b81 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -126,6 +126,87 @@ Parameters:
- `id` (required) - The ID or path of a group
- `project_id` (required) - The ID of a project
+## Update group
+
+Updates the project group. Only available to group owners and administrators.
+
+```
+PUT /groups/:id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the group |
+| `name` | string | no | The name of the group |
+| `path` | string | no | The path of the group |
+| `description` | string | no | The description of the group |
+| `visibility_level` | integer | no | The visibility level of the group. 0 for private, 10 for internal, 20 for public. |
+
+```bash
+curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/groups/5?name=Experimental"
+
+```
+
+Example response:
+
+```json
+{
+ "id": 5,
+ "name": "Experimental",
+ "path": "h5bp",
+ "description": "foo",
+ "visibility_level": 10,
+ "avatar_url": null,
+ "web_url": "http://gitlab.example.com/groups/h5bp",
+ "projects": [
+ {
+ "id": 9,
+ "description": "foo",
+ "default_branch": "master",
+ "tag_list": [],
+ "public": false,
+ "archived": false,
+ "visibility_level": 10,
+ "ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git",
+ "http_url_to_repo": "http://gitlab.example.com/h5bp/html5-boilerplate.git",
+ "web_url": "http://gitlab.example.com/h5bp/html5-boilerplate",
+ "name": "Html5 Boilerplate",
+ "name_with_namespace": "Experimental / Html5 Boilerplate",
+ "path": "html5-boilerplate",
+ "path_with_namespace": "h5bp/html5-boilerplate",
+ "issues_enabled": true,
+ "merge_requests_enabled": true,
+ "wiki_enabled": true,
+ "builds_enabled": true,
+ "snippets_enabled": true,
+ "created_at": "2016-04-05T21:40:50.169Z",
+ "last_activity_at": "2016-04-06T16:52:08.432Z",
+ "shared_runners_enabled": true,
+ "creator_id": 1,
+ "namespace": {
+ "id": 5,
+ "name": "Experimental",
+ "path": "h5bp",
+ "owner_id": null,
+ "created_at": "2016-04-05T21:40:49.152Z",
+ "updated_at": "2016-04-07T08:07:48.466Z",
+ "description": "foo",
+ "avatar": {
+ "url": null
+ },
+ "share_with_group_lock": false,
+ "visibility_level": 10
+ },
+ "avatar_url": null,
+ "star_count": 1,
+ "forks_count": 0,
+ "open_issues_count": 3,
+ "public_builds": true
+ }
+ ]
+}
+```
+
## Remove group
Removes group with all projects inside.
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 1c635a6cdcf..f09847aef95 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -351,6 +351,61 @@ DELETE /projects/:id/issues/:issue_id
curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85
```
+## Move an issue
+
+Moves an issue to a different project. If the operation is successful, a status
+code `201` together with moved issue is returned. If the project, issue, or
+target project is not found, error `404` is returned. If the target project
+equals the source project or the user has insufficient permissions to move an
+issue, error `400` together with an explaining error message is returned.
+
+```
+POST /projects/:id/issues/:issue_id/move
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `issue_id` | integer | yes | The ID of a project's issue |
+| `to_project_id` | integer | yes | The ID of the new project |
+
+```bash
+curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85/move
+```
+
+Example response:
+
+```json
+{
+ "id": 92,
+ "iid": 11,
+ "project_id": 5,
+ "title": "Sit voluptas tempora quisquam aut doloribus et.",
+ "description": "Repellat voluptas quibusdam voluptatem exercitationem.",
+ "state": "opened",
+ "created_at": "2016-04-05T21:41:45.652Z",
+ "updated_at": "2016-04-07T12:20:17.596Z",
+ "labels": [],
+ "milestone": null,
+ "assignee": {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/u/axel.block"
+ },
+ "author": {
+ "name": "Kris Steuber",
+ "username": "solon.cremin",
+ "id": 10,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/u/solon.cremin"
+ }
+}
+```
+
## Comments on issues
Comments are done via the [notes](notes.md) resource.
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 9168ab00d7e..2e0936f11b5 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -105,6 +105,53 @@ Parameters:
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+### Delete an issue note
+
+Deletes an existing note of an issue. On success, this API method returns 200
+and the deleted note. If the note does not exist, the API returns 404.
+
+```
+DELETE /projects/:id/issues/:issue_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `issue_id` | integer | yes | The ID of an issue |
+| `note_id` | integer | yes | The ID of a note |
+
+```bash
+curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/11/notes/636
+```
+
+Example Response:
+
+```json
+{
+ "id": 636,
+ "body": "This is a good idea.",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "username": "pipin",
+ "email": "admin@example.com",
+ "name": "Pip",
+ "state": "active",
+ "created_at": "2013-09-30T13:46:01Z",
+ "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/u/pipin"
+ },
+ "created_at": "2016-04-05T22:10:44.164Z",
+ "system": false,
+ "noteable_id": 11,
+ "noteable_type": "Issue",
+ "upvote": false,
+ "downvote": false
+}
+```
+
## Snippets
### List all snippet notes
@@ -182,6 +229,53 @@ Parameters:
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+### Delete a snippet note
+
+Deletes an existing note of a snippet. On success, this API method returns 200
+and the deleted note. If the note does not exist, the API returns 404.
+
+```
+DELETE /projects/:id/snippets/:snippet_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `snippet_id` | integer | yes | The ID of a snippet |
+| `note_id` | integer | yes | The ID of a note |
+
+```bash
+curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/snippets/52/notes/1659
+```
+
+Example Response:
+
+```json
+{
+ "id": 1659,
+ "body": "This is a good idea.",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "username": "pipin",
+ "email": "admin@example.com",
+ "name": "Pip",
+ "state": "active",
+ "created_at": "2013-09-30T13:46:01Z",
+ "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/u/pipin"
+ },
+ "created_at": "2016-04-06T16:51:53.239Z",
+ "system": false,
+ "noteable_id": 52,
+ "noteable_type": "Snippet",
+ "upvote": false,
+ "downvote": false
+}
+```
+
## Merge Requests
### List all merge request notes
@@ -262,3 +356,50 @@ Parameters:
- `merge_request_id` (required) - The ID of a merge request
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+
+### Delete a merge request note
+
+Deletes an existing note of a merge request. On success, this API method returns
+200 and the deleted note. If the note does not exist, the API returns 404.
+
+```
+DELETE /projects/:id/merge_requests/:merge_request_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `merge_request_id` | integer | yes | The ID of a merge request |
+| `note_id` | integer | yes | The ID of a note |
+
+```bash
+curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/7/notes/1602
+```
+
+Example Response:
+
+```json
+{
+ "id": 1602,
+ "body": "This is a good idea.",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "username": "pipin",
+ "email": "admin@example.com",
+ "name": "Pip",
+ "state": "active",
+ "created_at": "2013-09-30T13:46:01Z",
+ "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/u/pipin"
+ },
+ "created_at": "2016-04-05T22:11:59.923Z",
+ "system": false,
+ "noteable_id": 7,
+ "noteable_type": "MergeRequest",
+ "upvote": false,
+ "downvote": false
+}
+```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 3a909a2bc87..ab716c229dc 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -780,8 +780,10 @@ Parameters:
- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
- `user_id` (required) - The ID of a team member
-This method is idempotent and can be called multiple times with the same parameters.
-Revoking team membership for a user who is not currently a team member is considered success.
+This method removes the project member if the user has the proper access rights to do so.
+It returns a status code 403 if the member does not have the proper rights to perform this action.
+In all other cases this method is idempotent and revoking team membership for a user who is not
+currently a team member is considered success.
Please note that the returned JSON currently differs slightly. Thus you should not
rely on the returned JSON structure.
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 17d12e9cc62..ac9fac92f4c 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -38,6 +38,50 @@ Parameters:
]
```
+## Get a single repository tag
+
+Get a specific repository tag determined by its name. It returns `200` together
+with the tag information if the tag exists. It returns `404` if the tag does not
+exist.
+
+```
+GET /projects/:id/repository/tags/:tag_name
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `tag_name` | string | yes | The name of the tag |
+
+```bash
+curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/repository/tags/v1.0.0
+```
+
+Example Response:
+
+```json
+{
+ "name": "v5.0.0",
+ "message": null,
+ "commit": {
+ "id": "60a8ff033665e1207714d6670fcd7b65304ec02f",
+ "message": "v5.0.0\n",
+ "parent_ids": [
+ "f61c062ff8bcbdb00e0a1b3317a91aed6ceee06b"
+ ],
+ "authored_date": "2015-02-01T21:56:31.000+01:00",
+ "author_name": "Arthur Verschaeve",
+ "author_email": "contact@arthurverschaeve.be",
+ "committed_date": "2015-02-01T21:56:31.000+01:00",
+ "committer_name": "Arthur Verschaeve",
+ "committer_email": "contact@arthurverschaeve.be"
+ },
+ "release": null
+}
+```
+
## Create a new tag
Creates a new tag in the repository that points to the supplied ref.
@@ -148,4 +192,4 @@ Parameters:
"tag_name": "1.0.0",
"description": "Amazing release. Wow"
}
-``` \ No newline at end of file
+```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index f8f7d6a9ebe..e721e70a596 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -530,6 +530,16 @@ See the [omniauth integration document](../integration/omniauth.md)
GitLab can build your projects. To enable that feature you need GitLab Runners to do that for you.
Checkout the [GitLab Runner section](https://about.gitlab.com/gitlab-ci/#gitlab-runner) to install it
+### Adding your Trusted Proxies
+
+If you are using a reverse proxy on an separate machine, you may want to add the
+proxy to the trusted proxies list. Otherwise users will appear signed in from the
+proxy's IP address.
+
+You can add trusted proxies in `config/gitlab.yml` by customizing the `trusted_proxies`
+option in section 1. Save the file and [reconfigure GitLab](../administration/restart_gitlab.md)
+for the changes to take effect.
+
### Custom Redis Connection
If you'd like Resque to connect to a Redis server on a non-standard port or on a different host, you can configure its connection string via the `config/resque.yml` file.
diff --git a/doc/project_services/img/jira_service_page.png b/doc/project_services/img/jira_service_page.png
index 2b37eda3520..c225daa81e1 100644
--- a/doc/project_services/img/jira_service_page.png
+++ b/doc/project_services/img/jira_service_page.png
Binary files differ
diff --git a/doc/project_services/jira.md b/doc/project_services/jira.md
index 27170c1eb19..b626c746c79 100644
--- a/doc/project_services/jira.md
+++ b/doc/project_services/jira.md
@@ -1,9 +1,9 @@
# GitLab JIRA integration
-_**Note:**
+>**Note:**
Full JIRA integration was previously exclusive to GitLab Enterprise Edition.
With [GitLab 8.3 forward][8_3_post], this feature in now [backported][jira-ce]
-to GitLab Community Edition as well._
+to GitLab Community Edition as well.
---
@@ -88,8 +88,9 @@ password as they will be needed when configuring GitLab in the next section.
### Configuring GitLab
-_**Note:** The currently supported JIRA versions are v6.x and v7.x. and GitLab
-7.8 or higher is required._
+>**Note:**
+The currently supported JIRA versions are v6.x and v7.x. and GitLab
+7.8 or higher is required.
---
@@ -113,13 +114,24 @@ Fill in the required details on the page, as described in the table below.
| `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`. It is of the form: `https://<jira_host_url>/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 setting is very important to set up correctly. It is the ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot](img/jira_issues_workflow.png)). By default, this ID is set to `2` |
+| `JIRA issue transition` | This setting is very important to set up correctly. It is the ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. |
After saving the configuration, your GitLab project will be able to interact
with the linked JIRA project.
+For example, given the settings below:
+
+- the JIRA URL is `https://jira.example.com`
+- the project is named `GITLAB`
+- the user is named `gitlab`
+- the JIRA issue transition is 151 (based on the [JIRA issue transition][trans])
+
+the following screenshot shows how the JIRA service settings should look like.
+
![JIRA service page](img/jira_service_page.png)
+[trans]: img/jira_issues_workflow.png
+
---
## JIRA issues
diff --git a/doc/workflow/img/new_branch_from_issue.png b/doc/workflow/img/new_branch_from_issue.png
new file mode 100644
index 00000000000..394c139e17e
--- /dev/null
+++ b/doc/workflow/img/new_branch_from_issue.png
Binary files differ
diff --git a/doc/workflow/web_editor.md b/doc/workflow/web_editor.md
index 4a451d98953..5685a9d89dd 100644
--- a/doc/workflow/web_editor.md
+++ b/doc/workflow/web_editor.md
@@ -66,6 +66,35 @@ the target branch. Click **Create directory** to finish.
## Create a new branch
+There are multiple ways to create a branch from GitLab's web interface.
+
+### Create a new branch from an issue
+
+>**Note:**
+This feature was [introduced][ce-2808] in GitLab 8.6.
+
+In case your development workflow dictates to have an issue for every merge
+request, you can quickly create a branch right on the issue page which will be
+tied with the issue itself. You can see a **New Branch** button after the issue
+description, unless there is already a branch with the same name or a referenced
+merge request.
+
+![New Branch Button](img/new_branch_from_issue.png)
+
+Once you click it, a new branch will be created that diverges from the default
+branch of your project, by default `master`. The branch name will be based on
+the title of the issue and as suffix it will have its ID. Thus, the example
+screenshot above will yield a branch named
+`et-cum-et-sed-expedita-repellat-consequatur-ut-assumenda-numquam-rerum-2`.
+
+After the branch is created, you can edit files in the repository to fix
+the issue. When a merge request is created based on the newly created branch,
+the description field will automatically display the [issue closing pattern]
+`Closes #ID`, where `ID` the ID of the issue. This will close the issue once the
+merge request is merged.
+
+### Create a new branch from a project's dashboard
+
If you want to make changes to several files before creating a new merge
request, you can create a new branch up front. From a project's files page,
choose **New branch** from the dropdown.
@@ -118,3 +147,6 @@ appear that is labeled **Start a new merge request with these changes**. After
you commit the changes you will be taken to a new merge request form.
![Start a new merge request with these changes](img/web_editor_start_new_merge_request.png)
+
+[ce-2808]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2808
+[issue closing pattern]: ../customization/issue_closing.md
diff --git a/features/profile/notifications.feature b/features/profile/notifications.feature
index 55997d44dec..ef8743932f5 100644
--- a/features/profile/notifications.feature
+++ b/features/profile/notifications.feature
@@ -7,3 +7,9 @@ Feature: Profile Notifications
Scenario: I visit notifications tab
When I visit profile notifications page
Then I should see global notifications settings
+
+ @javascript
+ Scenario: I edit Project Notifications
+ Given I visit profile notifications page
+ When I select Mention setting from dropdown
+ Then I should see Notification saved message
diff --git a/features/steps/profile/notifications.rb b/features/steps/profile/notifications.rb
index 447ea6d9d10..a96f35ada51 100644
--- a/features/steps/profile/notifications.rb
+++ b/features/steps/profile/notifications.rb
@@ -9,4 +9,14 @@ class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps
step 'I should see global notifications settings' do
expect(page).to have_content "Notifications"
end
+
+ step 'I select Mention setting from dropdown' do
+ select 'mention', from: 'notification_setting_level'
+ end
+
+ step 'I should see Notification saved message' do
+ page.within '.flash-container' do
+ expect(page).to have_content 'Notification settings saved'
+ end
+ end
end
diff --git a/fixtures/emojis/digests.json b/fixtures/emojis/digests.json
index 18d6e93e0f4..41ca617847e 100644
--- a/fixtures/emojis/digests.json
+++ b/fixtures/emojis/digests.json
@@ -65,21 +65,41 @@
"digest": "fdddc2cd3618ec6661612581b8b93553cb086b0bb197e96aedf1bee8055e7bb4"
},
{
+ "name": "northeast_pointing_airplane",
+ "unicode": "1F6EA",
+ "digest": "fdddc2cd3618ec6661612581b8b93553cb086b0bb197e96aedf1bee8055e7bb4"
+ },
+ {
"name": "airplane_small",
"unicode": "1F6E9",
"digest": "f98b44422d6bf505b50330805ecf68013d035341f0b6487c3c05ad913eb5abd3"
},
{
+ "name": "small_airplane",
+ "unicode": "1F6E9",
+ "digest": "f98b44422d6bf505b50330805ecf68013d035341f0b6487c3c05ad913eb5abd3"
+ },
+ {
"name": "airplane_small_up",
"unicode": "1F6E8",
"digest": "029752b29a757c087dec60f45ea242e974fc181129e20390d5d4a2f90442091a"
},
{
+ "name": "up_pointing_small_airplane",
+ "unicode": "1F6E8",
+ "digest": "029752b29a757c087dec60f45ea242e974fc181129e20390d5d4a2f90442091a"
+ },
+ {
"name": "airplane_up",
"unicode": "1F6E7",
"digest": "ec45d4dbfce1f75dc59339417b1dcf5f1e1359cd9d04ff233babf359a3330e77"
},
{
+ "name": "up_pointing_airplane",
+ "unicode": "1F6E7",
+ "digest": "ec45d4dbfce1f75dc59339417b1dcf5f1e1359cd9d04ff233babf359a3330e77"
+ },
+ {
"name": "alarm_clock",
"unicode": "23F0",
"digest": "84ddd7b3b857c165410b7b44863e5354ca0f3591c3bfe56231f12c9f7531a96f"
@@ -150,11 +170,21 @@
"digest": "f2711991e8b386b2d5b12f296ce20a9b4b00ef91d6d67af2cf4e06abf2faa1dc"
},
{
+ "name": "left_anger_bubble",
+ "unicode": "1F5EE",
+ "digest": "f2711991e8b386b2d5b12f296ce20a9b4b00ef91d6d67af2cf4e06abf2faa1dc"
+ },
+ {
"name": "anger_right",
"unicode": "1F5EF",
"digest": "24b572d64c519251a3ae8844e8d66fd6955752aff99aebe7dc20179505a466c4"
},
{
+ "name": "right_anger_bubble",
+ "unicode": "1F5EF",
+ "digest": "24b572d64c519251a3ae8844e8d66fd6955752aff99aebe7dc20179505a466c4"
+ },
+ {
"name": "angry",
"unicode": "1F620",
"digest": "c4188ba70df99d8ccef5706d711176725d3dd50d62f065a177d68d85c7828107"
@@ -305,6 +335,11 @@
"digest": "0b7f27f545b616677c83d40ff957337477b2881459b4d3c839ae55e23797419f"
},
{
+ "name": "keycap_asterisk",
+ "unicode": "002A-20E3",
+ "digest": "0b7f27f545b616677c83d40ff957337477b2881459b4d3c839ae55e23797419f"
+ },
+ {
"name": "astonished",
"unicode": "1F632",
"digest": "58632b97e274ade5183752db2b3c5c4fe29effcd5a9720a8d01fa809b97023dc"
@@ -325,6 +360,11 @@
"digest": "cbce1725602efbb77a935cfae5407e4d75489ee988910296c7f6140665afc669"
},
{
+ "name": "atom_symbol",
+ "unicode": "269B",
+ "digest": "cbce1725602efbb77a935cfae5407e4d75489ee988910296c7f6140665afc669"
+ },
+ {
"name": "b",
"unicode": "1F171",
"digest": "9116256b3189977e37f6da7ddedf82bb29b0358829a4e8718fd59e51d9b86b3c"
@@ -400,11 +440,21 @@
"digest": "0455ea75612efe78354315b4c345953d2d559bb471d5b01c1adc1d6b74ed693a"
},
{
+ "name": "ballot_box_with_ballot",
+ "unicode": "1F5F3",
+ "digest": "0455ea75612efe78354315b4c345953d2d559bb471d5b01c1adc1d6b74ed693a"
+ },
+ {
"name": "ballot_box_check",
"unicode": "1F5F9",
"digest": "fc3ba16c009d963a4a0ea20a348ac98eee3c4c18c481df19a5ada0d1de7fcc15"
},
{
+ "name": "ballot_box_with_bold_check",
+ "unicode": "1F5F9",
+ "digest": "fc3ba16c009d963a4a0ea20a348ac98eee3c4c18c481df19a5ada0d1de7fcc15"
+ },
+ {
"name": "ballot_box_with_check",
"unicode": "2611",
"digest": "5f5cec7fe462557d31e8d2b836534c1e76d546cc0061236fa2af3667972b84aa"
@@ -415,11 +465,21 @@
"digest": "861dcfc2361298262587b5d0e163fed96a55c44636361f5b4a9ab1d6502b8928"
},
{
+ "name": "ballot_box_with_script_x",
+ "unicode": "1F5F5",
+ "digest": "861dcfc2361298262587b5d0e163fed96a55c44636361f5b4a9ab1d6502b8928"
+ },
+ {
"name": "ballot_x",
"unicode": "1F5F4",
"digest": "0b73b89847eb82bcad5664644c8af237e0aef6c3d8c94b7a5df94e05d0ebf4e1"
},
{
+ "name": "ballot_script_x",
+ "unicode": "1F5F4",
+ "digest": "0b73b89847eb82bcad5664644c8af237e0aef6c3d8c94b7a5df94e05d0ebf4e1"
+ },
+ {
"name": "bamboo",
"unicode": "1F38D",
"digest": "feb0cf2f1012a1c0649b8c66f7e96e2d8bcdefe879c5a52dab3e25c51009e3b2"
@@ -465,31 +525,61 @@
"digest": "e94beb69f631667479a80095bf313ceb3aa109d6ebb80f182722360a6d2a214e"
},
{
+ "name": "person_with_ball",
+ "unicode": "26F9",
+ "digest": "e94beb69f631667479a80095bf313ceb3aa109d6ebb80f182722360a6d2a214e"
+ },
+ {
"name": "basketball_player_tone1",
"unicode": "26F9-1F3FB",
"digest": "6fc77cf2f26ee18e9a3faea500d4277839f77633f31ee618a68c301f1ad32d90"
},
{
+ "name": "person_with_ball_tone1",
+ "unicode": "26F9-1F3FB",
+ "digest": "6fc77cf2f26ee18e9a3faea500d4277839f77633f31ee618a68c301f1ad32d90"
+ },
+ {
"name": "basketball_player_tone2",
"unicode": "26F9-1F3FC",
"digest": "6ee9060c24d92708e12a854fb0bdf5c717c90b8c0350d8aa40c278b41bfa12fc"
},
{
+ "name": "person_with_ball_tone2",
+ "unicode": "26F9-1F3FC",
+ "digest": "6ee9060c24d92708e12a854fb0bdf5c717c90b8c0350d8aa40c278b41bfa12fc"
+ },
+ {
"name": "basketball_player_tone3",
"unicode": "26F9-1F3FD",
"digest": "752e90dbfa7c7a9ae3f37de924e22f3c3d5a7e54dd41c8e8eb99cabb0dad73cf"
},
{
+ "name": "person_with_ball_tone3",
+ "unicode": "26F9-1F3FD",
+ "digest": "752e90dbfa7c7a9ae3f37de924e22f3c3d5a7e54dd41c8e8eb99cabb0dad73cf"
+ },
+ {
"name": "basketball_player_tone4",
"unicode": "26F9-1F3FE",
"digest": "38bedc3074e6243454d568d9b665f5764f1a3d983875651ce7a1cdb53da9f6c8"
},
{
+ "name": "person_with_ball_tone4",
+ "unicode": "26F9-1F3FE",
+ "digest": "38bedc3074e6243454d568d9b665f5764f1a3d983875651ce7a1cdb53da9f6c8"
+ },
+ {
"name": "basketball_player_tone5",
"unicode": "26F9-1F3FF",
"digest": "25ee1e84670d3db96d3ad098c859abd6b3448f55f668ce0c195ee2337a215de7"
},
{
+ "name": "person_with_ball_tone5",
+ "unicode": "26F9-1F3FF",
+ "digest": "25ee1e84670d3db96d3ad098c859abd6b3448f55f668ce0c195ee2337a215de7"
+ },
+ {
"name": "bath",
"unicode": "1F6C0",
"digest": "ae6301a6354630cd9dc06a5137f23f826d019c8298b2b012b6ff31b773a910b6"
@@ -535,11 +625,21 @@
"digest": "52855d75cfa4476ccc23c58b4afcb76ee48abb22a9a6081210c8accefdf33099"
},
{
+ "name": "beach_with_umbrella",
+ "unicode": "1F3D6",
+ "digest": "52855d75cfa4476ccc23c58b4afcb76ee48abb22a9a6081210c8accefdf33099"
+ },
+ {
"name": "beach_umbrella",
"unicode": "26F1",
"digest": "cefe8e195d21d3e0769d3bfe15170db9e57c86db9d31cacb19fcdc8d2191b661"
},
{
+ "name": "umbrella_on_ground",
+ "unicode": "26F1",
+ "digest": "cefe8e195d21d3e0769d3bfe15170db9e57c86db9d31cacb19fcdc8d2191b661"
+ },
+ {
"name": "bear",
"unicode": "1F43B",
"digest": "b5ac126875c20c82b9e3140b143233944a2e4132d781d0b575e83673988523cb"
@@ -585,6 +685,11 @@
"digest": "c15455f1b52ac26404b5c13a0e1070212ed1830026422873f4f6335e26e31259"
},
{
+ "name": "bellhop_bell",
+ "unicode": "1F6CE",
+ "digest": "c15455f1b52ac26404b5c13a0e1070212ed1830026422873f4f6335e26e31259"
+ },
+ {
"name": "bento",
"unicode": "1F371",
"digest": "d59314b17a8646d4a78fefb7b79f289f33d4aaea893fed4cad0b890df63395e7"
@@ -635,6 +740,11 @@
"digest": "81f8309318051255ed4dc18855a3cd3f8657a6f3b2d368caa531a57ce0e34235"
},
{
+ "name": "biohazard_sign",
+ "unicode": "2623",
+ "digest": "81f8309318051255ed4dc18855a3cd3f8657a6f3b2d368caa531a57ce0e34235"
+ },
+ {
"name": "bird",
"unicode": "1F426",
"digest": "3f219e5aa18e2f1febfd368ec133786cd2eab357db79984cb8ba07fed0eec7cd"
@@ -770,6 +880,11 @@
"digest": "1643ec51ff26fc1ac0c67859e202386398650bf2a996c82b68e1b73fa52abf7d"
},
{
+ "name": "bouquet_of_flowers",
+ "unicode": "1F395",
+ "digest": "1643ec51ff26fc1ac0c67859e202386398650bf2a996c82b68e1b73fa52abf7d"
+ },
+ {
"name": "bow",
"unicode": "1F647",
"digest": "5e260c38cfc80cd2f20ef78d982126dbf90934f7afa12c96d0b7b413beb6d4e0"
@@ -780,6 +895,11 @@
"digest": "1c23469256331ea4ff03c036f89f0e63ad3228c51faecba50129da99b7eaddf3"
},
{
+ "name": "archery",
+ "unicode": "1F3F9",
+ "digest": "1c23469256331ea4ff03c036f89f0e63ad3228c51faecba50129da99b7eaddf3"
+ },
+ {
"name": "bow_tone1",
"unicode": "1F647-1F3FB",
"digest": "d3ec7ef70b355ba310d6fae7130a4e4cd11526b6e219474b5678a2b3ba1077f0"
@@ -925,6 +1045,11 @@
"digest": "92493636cf086205d1e12cc19e613b84152ef10b8cd0215619a0fc813bfc9a7c"
},
{
+ "name": "bullhorn_with_sound_waves",
+ "unicode": "1F56C",
+ "digest": "92493636cf086205d1e12cc19e613b84152ef10b8cd0215619a0fc813bfc9a7c"
+ },
+ {
"name": "burrito",
"unicode": "1F32F",
"digest": "4babb1af1136ab2334d26495b0be779d0bcc9516fd956fc07ffde427d11122f0"
@@ -965,6 +1090,11 @@
"digest": "01b47b5c69c12b65fa4f4c0d580f2a98280d6116f4ad2cf8be378759008bcc3c"
},
{
+ "name": "pocket calculator",
+ "unicode": "1F5A9",
+ "digest": "01b47b5c69c12b65fa4f4c0d580f2a98280d6116f4ad2cf8be378759008bcc3c"
+ },
+ {
"name": "calendar",
"unicode": "1F4C6",
"digest": "00bb700dd88efbc43bc64263491cdf77965130b1dc23f31e682905c3dfe4040c"
@@ -975,6 +1105,11 @@
"digest": "1dd5da98bb435c0c3f632bc0a5c9fdde694de7aee752bf4bb85def086e788a2a"
},
{
+ "name": "spiral_calendar_pad",
+ "unicode": "1F5D3",
+ "digest": "1dd5da98bb435c0c3f632bc0a5c9fdde694de7aee752bf4bb85def086e788a2a"
+ },
+ {
"name": "calling",
"unicode": "1F4F2",
"digest": "2375828085f2efd17b8a5ebb3cfec1e420190913328a7a0dd9ff0f67c7249ffb"
@@ -1035,6 +1170,11 @@
"digest": "7d760ae1d44e6f4b2aac00895ca86b5743f8b5ca157ec2bd21ce2665e50ad23a"
},
{
+ "name": "card_file_box",
+ "unicode": "1F5C3",
+ "digest": "7d760ae1d44e6f4b2aac00895ca86b5743f8b5ca157ec2bd21ce2665e50ad23a"
+ },
+ {
"name": "card_index",
"unicode": "1F4C7",
"digest": "150950903eccb468981c58b87ed7c1ba44e17f52627d695f660ce96b3d9d6e8e"
@@ -1050,6 +1190,11 @@
"digest": "0b1625eea118060b51a70905c1eb3313ed632e989f70943eca16aa29fe8a34f2"
},
{
+ "name": "tape_cartridge",
+ "unicode": "1F5AD",
+ "digest": "0b1625eea118060b51a70905c1eb3313ed632e989f70943eca16aa29fe8a34f2"
+ },
+ {
"name": "cat",
"unicode": "1F431",
"digest": "002208c0c9165971853ee05cd05513175a913376a462a345a939d73401c6acb7"
@@ -1080,6 +1225,11 @@
"digest": "77395d3afe5cc10bfdc381120bae2ae4aefdaa96c529536413873a696c5fa713"
},
{
+ "name": "bottle_with_popping_cork",
+ "unicode": "1F37E",
+ "digest": "77395d3afe5cc10bfdc381120bae2ae4aefdaa96c529536413873a696c5fa713"
+ },
+ {
"name": "chart",
"unicode": "1F4B9",
"digest": "9fd5f8cd99988bbe0fabc89a0b23e28d1468641d2f9468e82b7148a1948d8236"
@@ -1105,6 +1255,11 @@
"digest": "5897036ba97b557868bb314fcee83b9d8a609c8447b270a0b3d34a29ce7496d1"
},
{
+ "name": "cheese_wedge",
+ "unicode": "1F9C0",
+ "digest": "5897036ba97b557868bb314fcee83b9d8a609c8447b270a0b3d34a29ce7496d1"
+ },
+ {
"name": "cherries",
"unicode": "1F352",
"digest": "5a0ba73039e4b56e3d16a1c70ad992f41af7a16f6d5ba4b5337bdf338276f0ff"
@@ -1170,6 +1325,11 @@
"digest": "c2530d12204eb518c5a3c8d7deba11170b1412fdf406aea05a69d4c026210d1b"
},
{
+ "name": "city_sunrise",
+ "unicode": "1F307",
+ "digest": "c2530d12204eb518c5a3c8d7deba11170b1412fdf406aea05a69d4c026210d1b"
+ },
+ {
"name": "cityscape",
"unicode": "1F3D9",
"digest": "15251a708d50fc721bd67d8abb2a517c0bade196df3b736e21d79191d749241f"
@@ -1230,6 +1390,11 @@
"digest": "c48314ccde8bf01acc2b1bc9a6b5aa7d796fc0c8769f80398bc74545fcef31ed"
},
{
+ "name": "mantlepiece_clock",
+ "unicode": "1F570",
+ "digest": "c48314ccde8bf01acc2b1bc9a6b5aa7d796fc0c8769f80398bc74545fcef31ed"
+ },
+ {
"name": "clock1",
"unicode": "1F550",
"digest": "c0550fa0c385920cbdb775bdaaa5e812097a484c4a32e35ebbafe3a364a4a438"
@@ -1355,6 +1520,11 @@
"digest": "67027b7e1a4d800a3ce7d731c21c098d1109d217159a27665eebb7e080fc2622"
},
{
+ "name": "clockwise_right_and_left_semicircle_arrows",
+ "unicode": "1F5D8",
+ "digest": "67027b7e1a4d800a3ce7d731c21c098d1109d217159a27665eebb7e080fc2622"
+ },
+ {
"name": "closed_book",
"unicode": "1F4D5",
"digest": "afd6dae5fa0f59330fc2adb922e92b3410a33a80a2667651718c7dac588010bc"
@@ -1380,21 +1550,41 @@
"digest": "fc9c85cc95f9c456635692c974f72b6d40e14943824b8129a21c47265c3416f4"
},
{
+ "name": "cloud_with_lightning",
+ "unicode": "1F329",
+ "digest": "fc9c85cc95f9c456635692c974f72b6d40e14943824b8129a21c47265c3416f4"
+ },
+ {
"name": "cloud_rain",
"unicode": "1F327",
"digest": "f4406e62ed98f6141ab70736f6d5c540023e805396db0346ee6b7082c3f5e8e2"
},
{
+ "name": "cloud_with_rain",
+ "unicode": "1F327",
+ "digest": "f4406e62ed98f6141ab70736f6d5c540023e805396db0346ee6b7082c3f5e8e2"
+ },
+ {
"name": "cloud_snow",
"unicode": "1F328",
"digest": "948990cd13dd927917208c026089519fcf8e258a8a284684ace67c9a2f9a8149"
},
{
+ "name": "cloud_with_snow",
+ "unicode": "1F328",
+ "digest": "948990cd13dd927917208c026089519fcf8e258a8a284684ace67c9a2f9a8149"
+ },
+ {
"name": "cloud_tornado",
"unicode": "1F32A",
"digest": "44753516d0bd05d47cfa6eb922aba570ba6a87f805f325772b2cff071460ead1"
},
{
+ "name": "cloud_with_tornado",
+ "unicode": "1F32A",
+ "digest": "44753516d0bd05d47cfa6eb922aba570ba6a87f805f325772b2cff071460ead1"
+ },
+ {
"name": "clubs",
"unicode": "2663",
"digest": "5fd19fadd3b0887a6a59819ffbbe33a061055c043200700c31be30e14a5d36d5"
@@ -1440,6 +1630,11 @@
"digest": "b27c30d74f205a8a3bd00a55ca17da7cf6ae3b65ae33e949755a4c6bd69a9fd3"
},
{
+ "name": "old_personal_computer",
+ "unicode": "1F5B3",
+ "digest": "b27c30d74f205a8a3bd00a55ca17da7cf6ae3b65ae33e949755a4c6bd69a9fd3"
+ },
+ {
"name": "confetti_ball",
"unicode": "1F38A",
"digest": "e77d0c0970d3d12e123e548639fc0fa3ce41668667e4be55baefc09dfaa22cb0"
@@ -1510,6 +1705,11 @@
"digest": "0ff52e6adf1927d356b27be5fef6bad2ad842be05e3a0bd16a17efe78e5676d9"
},
{
+ "name": "building_construction",
+ "unicode": "1F3D7",
+ "digest": "0ff52e6adf1927d356b27be5fef6bad2ad842be05e3a0bd16a17efe78e5676d9"
+ },
+ {
"name": "convenience_store",
"unicode": "1F3EA",
"digest": "1ff4351e4a4503f58ed5d35074a2112c681337e35ffe55332187481685573606"
@@ -1570,6 +1770,11 @@
"digest": "a93fffed194b404200495abda8772bb35539cfc8499eb0a9bf09c508afad6676"
},
{
+ "name": "couch_and_lamp",
+ "unicode": "1F6CB",
+ "digest": "a93fffed194b404200495abda8772bb35539cfc8499eb0a9bf09c508afad6676"
+ },
+ {
"name": "couple",
"unicode": "1F46B",
"digest": "97fe611a613216a1788f9bd88a9deb4714ee123a66b5fd3d0ac916fbb4da7304"
@@ -1580,6 +1785,11 @@
"digest": "3ae6fbf3ba168256ea85c756ac1e7b83fdb8b780d33f06128ed80706ff627eea"
},
{
+ "name": "couple_with_heart_mm",
+ "unicode": "1F468-2764-1F468",
+ "digest": "3ae6fbf3ba168256ea85c756ac1e7b83fdb8b780d33f06128ed80706ff627eea"
+ },
+ {
"name": "couple_with_heart",
"unicode": "1F491",
"digest": "d9701173a5e8dff052ab6a15a42494dbb61dc7146d3734c82916abc9c05f76db"
@@ -1590,6 +1800,11 @@
"digest": "d2a2ec29c1a1234ea0aa1d9fc6707cf8be8bb36ea8b92523ffa1c3071bcf0b06"
},
{
+ "name": "couple_with_heart_ww",
+ "unicode": "1F469-2764-1F469",
+ "digest": "d2a2ec29c1a1234ea0aa1d9fc6707cf8be8bb36ea8b92523ffa1c3071bcf0b06"
+ },
+ {
"name": "couplekiss",
"unicode": "1F48F",
"digest": "e722730de82397da7c8f88d79319b391e8f01fbe4a9133850cc92ad34e77bd82"
@@ -1615,6 +1830,11 @@
"digest": "0f3351c2e68a8d47d27b45a9901be6160de0f9a291bd8680df84d0fc679bcb31"
},
{
+ "name": "lower_left_crayon",
+ "unicode": "1F58D",
+ "digest": "0f3351c2e68a8d47d27b45a9901be6160de0f9a291bd8680df84d0fc679bcb31"
+ },
+ {
"name": "credit_card",
"unicode": "1F4B3",
"digest": "708c0e7008e06e5d1b3b4e68a7e0ada9f4ae22ab6c28285d81a340f913fd9a84"
@@ -1630,6 +1850,11 @@
"digest": "00eb11254e887c71db5e8945ad211e9e0280f1e02f4b77a4799b64bba2bbe9b3"
},
{
+ "name": "cricket_bat_ball",
+ "unicode": "1F3CF",
+ "digest": "00eb11254e887c71db5e8945ad211e9e0280f1e02f4b77a4799b64bba2bbe9b3"
+ },
+ {
"name": "crocodile",
"unicode": "1F40A",
"digest": "99abcb42264d40d2450aaca8c3759a019bfd600a311cf3027243f1ca200d4639"
@@ -1640,21 +1865,41 @@
"digest": "a6e3c345cf6aa2ce690b66454066b53ef5b1dab2ed635e21f1586b1dffc5df42"
},
{
+ "name": "latin_cross",
+ "unicode": "271D",
+ "digest": "a6e3c345cf6aa2ce690b66454066b53ef5b1dab2ed635e21f1586b1dffc5df42"
+ },
+ {
"name": "cross_heavy",
"unicode": "1F547",
"digest": "2e37c26b9bad0beb019c7f3e7a3892352d0ad9ca1b90c4333d42e8d56680be70"
},
{
+ "name": "heavy_latin_cross",
+ "unicode": "1F547",
+ "digest": "2e37c26b9bad0beb019c7f3e7a3892352d0ad9ca1b90c4333d42e8d56680be70"
+ },
+ {
"name": "cross_white",
"unicode": "1F546",
"digest": "3452e667010d7e49a51d7e1f4ba8ed4f303e33ed43255a051e9a18832a1efba6"
},
{
+ "name": "white_latin_cross",
+ "unicode": "1F546",
+ "digest": "3452e667010d7e49a51d7e1f4ba8ed4f303e33ed43255a051e9a18832a1efba6"
+ },
+ {
"name": "crossbones",
"unicode": "1F571",
"digest": "f5e7ce293c1a3282711073e68f033a3876e8428d1218cb2f8294630f9124e584"
},
{
+ "name": "black_skull_and_crossbones",
+ "unicode": "1F571",
+ "digest": "f5e7ce293c1a3282711073e68f033a3876e8428d1218cb2f8294630f9124e584"
+ },
+ {
"name": "crossed_flags",
"unicode": "1F38C",
"digest": "d4da057db289bec83f0106a94c89bd0cd9b52c7c7f8bc69bc8cbce480d53e12b"
@@ -1675,6 +1920,11 @@
"digest": "90519c46ddfb63e71bc76661953da9041e5f0b97e9f8a7a8696518b4d529f3dd"
},
{
+ "name": "passenger_ship",
+ "unicode": "1F6F3",
+ "digest": "90519c46ddfb63e71bc76661953da9041e5f0b97e9f8a7a8696518b4d529f3dd"
+ },
+ {
"name": "cry",
"unicode": "1F622",
"digest": "2d6a096796222c29b050f74db6b5aff9b9f61390c5eb56e45d1801918751002f"
@@ -1730,6 +1980,11 @@
"digest": "377060a7ce930566a4732b361be98e8a193a546846dfbba2a00abeeef41d1976"
},
{
+ "name": "dagger_knife",
+ "unicode": "1F5E1",
+ "digest": "377060a7ce930566a4732b361be98e8a193a546846dfbba2a00abeeef41d1976"
+ },
+ {
"name": "dancer",
"unicode": "1F483",
"digest": "e050db55afbb968e02219a58c7e82b824848d299a4df64f0d08d4e1872816203"
@@ -1815,6 +2070,11 @@
"digest": "ba46323e695918e7253f1013cb991efb09790581c74c07c38bc5e10a20b8e8de"
},
{
+ "name": "desktop_computer",
+ "unicode": "1F5A5",
+ "digest": "ba46323e695918e7253f1013cb991efb09790581c74c07c38bc5e10a20b8e8de"
+ },
+ {
"name": "desktop_window",
"unicode": "1F5D4",
"digest": "d5b6c4a847e2a96f97f50fd353a22cb121915cb1d7bbc0f02df38769819b6b7e"
@@ -1845,6 +2105,11 @@
"digest": "bf4c303452a4c0b4986925041dbec5b7e478060d560630b7c5bc2f997fcad668"
},
{
+ "name": "card_index_dividers",
+ "unicode": "1F5C2",
+ "digest": "bf4c303452a4c0b4986925041dbec5b7e478060d560630b7c5bc2f997fcad668"
+ },
+ {
"name": "dizzy",
"unicode": "1F4AB",
"digest": "d6fba9b906f0eabd46686e416273a2ca6634249374385f2abf7ed284f0eef995"
@@ -1870,6 +2135,11 @@
"digest": "29407b12409c9673f3d89ef1f86ee50cbc7ed53b1870e33b4a29bbc609017f72"
},
{
+ "name": "document_with_text",
+ "unicode": "1F5B9",
+ "digest": "29407b12409c9673f3d89ef1f86ee50cbc7ed53b1870e33b4a29bbc609017f72"
+ },
+ {
"name": "dog",
"unicode": "1F436",
"digest": "c7b729de8a0967b1f38c3fa5ded94e77e329588caeaaf43abfd1090f420e62bf"
@@ -1910,6 +2180,11 @@
"digest": "4e2e9c47e5632efe6ccf945d61dbc2f1155a2e52905e17f307b502a2c951bdb8"
},
{
+ "name": "dove_of_peace",
+ "unicode": "1F54A",
+ "digest": "4e2e9c47e5632efe6ccf945d61dbc2f1155a2e52905e17f307b502a2c951bdb8"
+ },
+ {
"name": "dragon",
"unicode": "1F409",
"digest": "d7d016568b54d67017681a075fb799d4a2a790ecfa2946d02dbcee629eb4975d"
@@ -1945,6 +2220,11 @@
"digest": "12135310cfedc091d120426f5b132df82b538c5fcad458bf6b21588f353c3adb"
},
{
+ "name": "email",
+ "unicode": "1F4E7",
+ "digest": "12135310cfedc091d120426f5b132df82b538c5fcad458bf6b21588f353c3adb"
+ },
+ {
"name": "ear",
"unicode": "1F442",
"digest": "70ba1103a34e68590d91a3b6f8acdbad3b1c65e46e31e26ee1cb855c1e21095e"
@@ -2045,21 +2325,41 @@
"digest": "bc60b6d375feee00758a94a05b42eeb165f4084b20eb3e6012b72faa221f7e75"
},
{
+ "name": "back_of_envelope",
+ "unicode": "1F582",
+ "digest": "bc60b6d375feee00758a94a05b42eeb165f4084b20eb3e6012b72faa221f7e75"
+ },
+ {
"name": "envelope_flying",
"unicode": "1F585",
"digest": "9d6b6ca4c08006062a6f11948de3e15b13cf5c458967e39a9358665a8e13e214"
},
{
+ "name": "flying_envelope",
+ "unicode": "1F585",
+ "digest": "9d6b6ca4c08006062a6f11948de3e15b13cf5c458967e39a9358665a8e13e214"
+ },
+ {
"name": "envelope_stamped",
"unicode": "1F583",
"digest": "f6102aea7283ddc136bfeb09589573420b9279105045fc6b965c1633c1297468"
},
{
+ "name": "stamped_envelope",
+ "unicode": "1F583",
+ "digest": "f6102aea7283ddc136bfeb09589573420b9279105045fc6b965c1633c1297468"
+ },
+ {
"name": "envelope_stamped_pen",
"unicode": "1F586",
"digest": "80ea471318d1e04f8e525ff236b3cd4a4c864e66c6246b6aad77d92f56895f33"
},
{
+ "name": "pen_over_stamped_envelope",
+ "unicode": "1F586",
+ "digest": "80ea471318d1e04f8e525ff236b3cd4a4c864e66c6246b6aad77d92f56895f33"
+ },
+ {
"name": "envelope_with_arrow",
"unicode": "1F4E9",
"digest": "c1ba19b5e7cf64c547ac46eee139e6af70700d49ab511a96e6828c30feb116bc"
@@ -2255,31 +2555,61 @@
"digest": "0c542ac3141e8f2e74767acd0eb399c2d68c779cb78bf16d437ad3b1f8134ad9"
},
{
+ "name": "white_down_pointing_left_hand_index",
+ "unicode": "1F597",
+ "digest": "0c542ac3141e8f2e74767acd0eb399c2d68c779cb78bf16d437ad3b1f8134ad9"
+ },
+ {
"name": "finger_pointing_down2",
"unicode": "1F59F",
"digest": "c5b128a232cbf518544802a2ae1459368274297163721fa05d0103cf95b2b1ee"
},
{
+ "name": "sideways_white_down_pointing_index",
+ "unicode": "1F59F",
+ "digest": "c5b128a232cbf518544802a2ae1459368274297163721fa05d0103cf95b2b1ee"
+ },
+ {
"name": "finger_pointing_left",
"unicode": "1F598",
"digest": "d178ece691e2091be08db77fda9cf05462934628557358a8cb6222587b291f7e"
},
{
+ "name": "sideways_white_left_pointing_index",
+ "unicode": "1F598",
+ "digest": "d178ece691e2091be08db77fda9cf05462934628557358a8cb6222587b291f7e"
+ },
+ {
"name": "finger_pointing_right",
"unicode": "1F599",
"digest": "a412a47544d8f401f9181f8826c5fa3d6b42a1d76f6926963c2d9cd2a01be06d"
},
{
+ "name": "sideways_white_right_pointing_index",
+ "unicode": "1F599",
+ "digest": "a412a47544d8f401f9181f8826c5fa3d6b42a1d76f6926963c2d9cd2a01be06d"
+ },
+ {
"name": "finger_pointing_up",
"unicode": "1F59E",
"digest": "32c2ccab52aa318a47c816d1bcf9c076e667c9ef3e64ce37d7ba7e827238690d"
},
{
+ "name": "sideways_white_up_pointing_index",
+ "unicode": "1F59E",
+ "digest": "32c2ccab52aa318a47c816d1bcf9c076e667c9ef3e64ce37d7ba7e827238690d"
+ },
+ {
"name": "fire",
"unicode": "1F525",
"digest": "b44311874681135acbb5e7226febe4365c732da3a9617f10d7074a3b1ade1641"
},
{
+ "name": "flame",
+ "unicode": "1F525",
+ "digest": "b44311874681135acbb5e7226febe4365c732da3a9617f10d7074a3b1ade1641"
+ },
+ {
"name": "fire_engine",
"unicode": "1F692",
"digest": "3ae03fa34a7088ada95458eb4ee3e97691b3489149f6bbc168086f0483ed3bb2"
@@ -2290,6 +2620,11 @@
"digest": "e2482c450136d373f74dfafddf502e0b675eb5d2e1e1c645f163db0e4d15fbb6"
},
{
+ "name": "oncoming_fire_engine",
+ "unicode": "1F6F1",
+ "digest": "e2482c450136d373f74dfafddf502e0b675eb5d2e1e1c645f163db0e4d15fbb6"
+ },
+ {
"name": "fireworks",
"unicode": "1F386",
"digest": "3dee83a27c406960253ca1460eb88a599c7b81506051b69605a421b17fe8282c"
@@ -2360,1296 +2695,2596 @@
"digest": "d9db1edeb709824a1083c2bba79ca5f683ed0edded35918bb167d1ee7396c8da"
},
{
+ "name": "ac",
+ "unicode": "1F1E6-1F1E8",
+ "digest": "d9db1edeb709824a1083c2bba79ca5f683ed0edded35918bb167d1ee7396c8da"
+ },
+ {
"name": "flag_ad",
"unicode": "1F1E6-1F1E9",
"digest": "04a8c1745d9b8b20e903302379f2557e8082f72e33878db4cb2cd6b33eb97952"
},
{
+ "name": "ad",
+ "unicode": "1F1E6-1F1E9",
+ "digest": "04a8c1745d9b8b20e903302379f2557e8082f72e33878db4cb2cd6b33eb97952"
+ },
+ {
"name": "flag_ae",
"unicode": "1F1E6-1F1EA",
"digest": "868324ac2e7bea1547f5de95f39633b77b8d62f3b3433b3d1a4ee96d169a09cd"
},
{
+ "name": "ae",
+ "unicode": "1F1E6-1F1EA",
+ "digest": "868324ac2e7bea1547f5de95f39633b77b8d62f3b3433b3d1a4ee96d169a09cd"
+ },
+ {
"name": "flag_af",
"unicode": "1F1E6-1F1EB",
"digest": "9a94458519e9db5d6cf1557e54fdf62d7e48aaf7de25744a093ec8f284656226"
},
{
+ "name": "af",
+ "unicode": "1F1E6-1F1EB",
+ "digest": "9a94458519e9db5d6cf1557e54fdf62d7e48aaf7de25744a093ec8f284656226"
+ },
+ {
"name": "flag_ag",
"unicode": "1F1E6-1F1EC",
"digest": "ea59fabc2bd9024df06a59a34412f52bebfeb03eb6abd73d8fe153e3a68e28f4"
},
{
+ "name": "ag",
+ "unicode": "1F1E6-1F1EC",
+ "digest": "ea59fabc2bd9024df06a59a34412f52bebfeb03eb6abd73d8fe153e3a68e28f4"
+ },
+ {
"name": "flag_ai",
"unicode": "1F1E6-1F1EE",
"digest": "75676ded736ad2ebb921e9fd8ebfef49819a35c3dcf005bbc3b7e8c6e75178f2"
},
{
+ "name": "ai",
+ "unicode": "1F1E6-1F1EE",
+ "digest": "75676ded736ad2ebb921e9fd8ebfef49819a35c3dcf005bbc3b7e8c6e75178f2"
+ },
+ {
"name": "flag_al",
"unicode": "1F1E6-1F1F1",
"digest": "77b835dcff399b609e2479cbf10f08344c8fc277370ba8e4540165ca15563847"
},
{
+ "name": "al",
+ "unicode": "1F1E6-1F1F1",
+ "digest": "77b835dcff399b609e2479cbf10f08344c8fc277370ba8e4540165ca15563847"
+ },
+ {
"name": "flag_am",
"unicode": "1F1E6-1F1F2",
"digest": "3b820c628dd5a93137f7288a43553778f60b0beea4c0a239d063893c0723e73d"
},
{
+ "name": "am",
+ "unicode": "1F1E6-1F1F2",
+ "digest": "3b820c628dd5a93137f7288a43553778f60b0beea4c0a239d063893c0723e73d"
+ },
+ {
"name": "flag_ao",
"unicode": "1F1E6-1F1F4",
"digest": "d26439d4ecbe8b67bb1ae9753454505358ebb6b802624f19800471e53ee27187"
},
{
+ "name": "ao",
+ "unicode": "1F1E6-1F1F4",
+ "digest": "d26439d4ecbe8b67bb1ae9753454505358ebb6b802624f19800471e53ee27187"
+ },
+ {
"name": "flag_aq",
"unicode": "1F1E6-1F1F6",
"digest": "6b0b4e800d88ab289ae4b6d449bfa115e92543958b477d13ad348468a74e4616"
},
{
+ "name": "aq",
+ "unicode": "1F1E6-1F1F6",
+ "digest": "6b0b4e800d88ab289ae4b6d449bfa115e92543958b477d13ad348468a74e4616"
+ },
+ {
"name": "flag_ar",
"unicode": "1F1E6-1F1F7",
"digest": "ca76db601dd3f5794f1caace8ab5641fe3786b86e4ae030706162f0ce07d27b3"
},
{
+ "name": "ar",
+ "unicode": "1F1E6-1F1F7",
+ "digest": "ca76db601dd3f5794f1caace8ab5641fe3786b86e4ae030706162f0ce07d27b3"
+ },
+ {
"name": "flag_as",
"unicode": "1F1E6-1F1F8",
"digest": "170e1dde0e3fd2e0f2149de5cc8845e15580cc0412e81a643d61bd387de16141"
},
{
+ "name": "as",
+ "unicode": "1F1E6-1F1F8",
+ "digest": "170e1dde0e3fd2e0f2149de5cc8845e15580cc0412e81a643d61bd387de16141"
+ },
+ {
"name": "flag_at",
"unicode": "1F1E6-1F1F9",
"digest": "0ab3675a16b4988e87c81e87453c160d6616c7be76247f54c471dc63aa8b42ba"
},
{
+ "name": "at",
+ "unicode": "1F1E6-1F1F9",
+ "digest": "0ab3675a16b4988e87c81e87453c160d6616c7be76247f54c471dc63aa8b42ba"
+ },
+ {
"name": "flag_au",
"unicode": "1F1E6-1F1FA",
"digest": "b6f17d3dfd3547c069a0b6cddd4cf44fb8ce1d1d300e24284fb292ac142537e3"
},
{
+ "name": "au",
+ "unicode": "1F1E6-1F1FA",
+ "digest": "b6f17d3dfd3547c069a0b6cddd4cf44fb8ce1d1d300e24284fb292ac142537e3"
+ },
+ {
"name": "flag_aw",
"unicode": "1F1E6-1F1FC",
"digest": "7857bc907f04dfb7ccc4401c05034ad8afb6383a022db77973cfcafa4d6c16c8"
},
{
+ "name": "aw",
+ "unicode": "1F1E6-1F1FC",
+ "digest": "7857bc907f04dfb7ccc4401c05034ad8afb6383a022db77973cfcafa4d6c16c8"
+ },
+ {
"name": "flag_ax",
"unicode": "1F1E6-1F1FD",
"digest": "ab8f1fd4af7c220a54d478cec5a9f7f3beb5fc83439c448f3ac9848af8391ac1"
},
{
+ "name": "ax",
+ "unicode": "1F1E6-1F1FD",
+ "digest": "ab8f1fd4af7c220a54d478cec5a9f7f3beb5fc83439c448f3ac9848af8391ac1"
+ },
+ {
"name": "flag_az",
"unicode": "1F1E6-1F1FF",
"digest": "187cc7b6d39800c5910a34409db1e6b1d8aac808c72a93e922a419d9b054fd0b"
},
{
+ "name": "az",
+ "unicode": "1F1E6-1F1FF",
+ "digest": "187cc7b6d39800c5910a34409db1e6b1d8aac808c72a93e922a419d9b054fd0b"
+ },
+ {
"name": "flag_ba",
"unicode": "1F1E7-1F1E6",
"digest": "cd22c744213087384cf79ed314742026787212c9ceb6999ed166534670f7864a"
},
{
+ "name": "ba",
+ "unicode": "1F1E7-1F1E6",
+ "digest": "cd22c744213087384cf79ed314742026787212c9ceb6999ed166534670f7864a"
+ },
+ {
"name": "flag_bb",
"unicode": "1F1E7-1F1E7",
"digest": "44ff0a48ac2d2180374baa58b1b7c64f26d0d151a48811eb08ffa20758104512"
},
{
+ "name": "bb",
+ "unicode": "1F1E7-1F1E7",
+ "digest": "44ff0a48ac2d2180374baa58b1b7c64f26d0d151a48811eb08ffa20758104512"
+ },
+ {
"name": "flag_bd",
"unicode": "1F1E7-1F1E9",
"digest": "c18793d2b963458607a0bab94c57e62c8278fce870e96fd8dda78067a8fbde18"
},
{
+ "name": "bd",
+ "unicode": "1F1E7-1F1E9",
+ "digest": "c18793d2b963458607a0bab94c57e62c8278fce870e96fd8dda78067a8fbde18"
+ },
+ {
"name": "flag_be",
"unicode": "1F1E7-1F1EA",
"digest": "6e6ccfca064a43b93c8acc04a9425f95af204198022ca20b9ee6c491e99ad950"
},
{
+ "name": "be",
+ "unicode": "1F1E7-1F1EA",
+ "digest": "6e6ccfca064a43b93c8acc04a9425f95af204198022ca20b9ee6c491e99ad950"
+ },
+ {
"name": "flag_bf",
"unicode": "1F1E7-1F1EB",
"digest": "d69c0394a1c7cb6323f54f024b7d740c728f229ca5e1b54ac374d5024f5470a5"
},
{
+ "name": "bf",
+ "unicode": "1F1E7-1F1EB",
+ "digest": "d69c0394a1c7cb6323f54f024b7d740c728f229ca5e1b54ac374d5024f5470a5"
+ },
+ {
"name": "flag_bg",
"unicode": "1F1E7-1F1EC",
"digest": "413a270caf4a9155e84bdba6c9512277f5642246f6ba8d701383a5eeb02f7e95"
},
{
+ "name": "bg",
+ "unicode": "1F1E7-1F1EC",
+ "digest": "413a270caf4a9155e84bdba6c9512277f5642246f6ba8d701383a5eeb02f7e95"
+ },
+ {
"name": "flag_bh",
"unicode": "1F1E7-1F1ED",
"digest": "9243ed65d7f24c824c2a3207335a2d4ad25251258547c16d0b7b7cbb9df6f8de"
},
{
+ "name": "bh",
+ "unicode": "1F1E7-1F1ED",
+ "digest": "9243ed65d7f24c824c2a3207335a2d4ad25251258547c16d0b7b7cbb9df6f8de"
+ },
+ {
"name": "flag_bi",
"unicode": "1F1E7-1F1EE",
"digest": "63056519030524b2d2dcd47448267d817205dbd6b98075c97f011a8f1d4d1a4b"
},
{
+ "name": "bi",
+ "unicode": "1F1E7-1F1EE",
+ "digest": "63056519030524b2d2dcd47448267d817205dbd6b98075c97f011a8f1d4d1a4b"
+ },
+ {
"name": "flag_bj",
"unicode": "1F1E7-1F1EF",
"digest": "93b245eed85d22260d27d1a8c77f51fb3439309e09b2aeca6cd504dbea77b509"
},
{
+ "name": "bj",
+ "unicode": "1F1E7-1F1EF",
+ "digest": "93b245eed85d22260d27d1a8c77f51fb3439309e09b2aeca6cd504dbea77b509"
+ },
+ {
"name": "flag_bl",
"unicode": "1F1E7-1F1F1",
"digest": "5e1e478deaf02bbaa26595e4cefc5f5c9bec6105ce521b7b9ab4fa5e7a452c14"
},
{
+ "name": "bl",
+ "unicode": "1F1E7-1F1F1",
+ "digest": "5e1e478deaf02bbaa26595e4cefc5f5c9bec6105ce521b7b9ab4fa5e7a452c14"
+ },
+ {
"name": "flag_black",
"unicode": "1F3F4",
"digest": "df131e5c28e9f51dea53fe7f33551f91d420f7d686b7a62980f0154c6b5357a6"
},
{
+ "name": "waving_black_flag",
+ "unicode": "1F3F4",
+ "digest": "df131e5c28e9f51dea53fe7f33551f91d420f7d686b7a62980f0154c6b5357a6"
+ },
+ {
"name": "flag_bm",
"unicode": "1F1E7-1F1F2",
"digest": "9dcd9e60faebe7f93eb19157e99f2ad654a8145c61738de96e6ecd11a246764a"
},
{
+ "name": "bm",
+ "unicode": "1F1E7-1F1F2",
+ "digest": "9dcd9e60faebe7f93eb19157e99f2ad654a8145c61738de96e6ecd11a246764a"
+ },
+ {
"name": "flag_bn",
"unicode": "1F1E7-1F1F3",
"digest": "078af6ca481a77871ba005e251a46ce63951c27b1b0cd33b9c1d0d31d349bc1a"
},
{
+ "name": "bn",
+ "unicode": "1F1E7-1F1F3",
+ "digest": "078af6ca481a77871ba005e251a46ce63951c27b1b0cd33b9c1d0d31d349bc1a"
+ },
+ {
"name": "flag_bo",
"unicode": "1F1E7-1F1F4",
"digest": "92516d04e922a3bcbabe2e7619194bc972c09ba97576e8155f9829c397a71d8c"
},
{
+ "name": "bo",
+ "unicode": "1F1E7-1F1F4",
+ "digest": "92516d04e922a3bcbabe2e7619194bc972c09ba97576e8155f9829c397a71d8c"
+ },
+ {
"name": "flag_bq",
"unicode": "1F1E7-1F1F6",
"digest": "7832df5267a2bb8dddb83aeb11162ce79aeebdb718f2ac0e54adcf3d87936171"
},
{
+ "name": "bq",
+ "unicode": "1F1E7-1F1F6",
+ "digest": "7832df5267a2bb8dddb83aeb11162ce79aeebdb718f2ac0e54adcf3d87936171"
+ },
+ {
"name": "flag_br",
"unicode": "1F1E7-1F1F7",
"digest": "aabcc1c082124045ed214f7d9778d8e2ed791ebb8433defea91db458658abeec"
},
{
+ "name": "br",
+ "unicode": "1F1E7-1F1F7",
+ "digest": "aabcc1c082124045ed214f7d9778d8e2ed791ebb8433defea91db458658abeec"
+ },
+ {
"name": "flag_bs",
"unicode": "1F1E7-1F1F8",
"digest": "f628f39003608e181696634929522884165e27ccef55270293f92eeef991635f"
},
{
+ "name": "bs",
+ "unicode": "1F1E7-1F1F8",
+ "digest": "f628f39003608e181696634929522884165e27ccef55270293f92eeef991635f"
+ },
+ {
"name": "flag_bt",
"unicode": "1F1E7-1F1F9",
"digest": "af24a8ab34815da04c3e5af49a47449e0de93b068957cbda695816d0f830ca12"
},
{
+ "name": "bt",
+ "unicode": "1F1E7-1F1F9",
+ "digest": "af24a8ab34815da04c3e5af49a47449e0de93b068957cbda695816d0f830ca12"
+ },
+ {
"name": "flag_bv",
"unicode": "1F1E7-1F1FB",
"digest": "ff0037f6eed95d4bb5f2b502902360e1ff41426e2896daf3e0730cef1f8f7e41"
},
{
+ "name": "bv",
+ "unicode": "1F1E7-1F1FB",
+ "digest": "ff0037f6eed95d4bb5f2b502902360e1ff41426e2896daf3e0730cef1f8f7e41"
+ },
+ {
"name": "flag_bw",
"unicode": "1F1E7-1F1FC",
"digest": "3e3241ecb97946cc3e467b083d113a57dd305595e1512d4da18cc403e8689c1d"
},
{
+ "name": "bw",
+ "unicode": "1F1E7-1F1FC",
+ "digest": "3e3241ecb97946cc3e467b083d113a57dd305595e1512d4da18cc403e8689c1d"
+ },
+ {
"name": "flag_by",
"unicode": "1F1E7-1F1FE",
"digest": "bdd21885c6fac475241884a44149b887297772e17617ee59dd9fe8518d52cf3d"
},
{
+ "name": "by",
+ "unicode": "1F1E7-1F1FE",
+ "digest": "bdd21885c6fac475241884a44149b887297772e17617ee59dd9fe8518d52cf3d"
+ },
+ {
"name": "flag_bz",
"unicode": "1F1E7-1F1FF",
"digest": "21c16e1da641af004576000bf1db44b9a1e0fccfddc775e96022721c2f18eeea"
},
{
+ "name": "bz",
+ "unicode": "1F1E7-1F1FF",
+ "digest": "21c16e1da641af004576000bf1db44b9a1e0fccfddc775e96022721c2f18eeea"
+ },
+ {
"name": "flag_ca",
"unicode": "1F1E8-1F1E6",
"digest": "0d00e459084d58d3ea9c60488a9e51bf45f71b77f1600f190225d5ca6ca6c796"
},
{
+ "name": "ca",
+ "unicode": "1F1E8-1F1E6",
+ "digest": "0d00e459084d58d3ea9c60488a9e51bf45f71b77f1600f190225d5ca6ca6c796"
+ },
+ {
"name": "flag_cc",
"unicode": "1F1E8-1F1E8",
"digest": "86ab27164603ef0f1f83fe898eda6fbb7bc5709f2518f5577f00817860806a7b"
},
{
+ "name": "cc",
+ "unicode": "1F1E8-1F1E8",
+ "digest": "86ab27164603ef0f1f83fe898eda6fbb7bc5709f2518f5577f00817860806a7b"
+ },
+ {
"name": "flag_cd",
"unicode": "1F1E8-1F1E9",
"digest": "fdc2796530ada4bd0bae37ace4bbe707b321b287dcd64568f8e01d3a9df56066"
},
{
+ "name": "congo",
+ "unicode": "1F1E8-1F1E9",
+ "digest": "fdc2796530ada4bd0bae37ace4bbe707b321b287dcd64568f8e01d3a9df56066"
+ },
+ {
"name": "flag_cf",
"unicode": "1F1E8-1F1EB",
"digest": "5943bec02bede0931e21e7c34a68f375499f60a34883cc1edf2f21e9834b15ce"
},
{
+ "name": "cf",
+ "unicode": "1F1E8-1F1EB",
+ "digest": "5943bec02bede0931e21e7c34a68f375499f60a34883cc1edf2f21e9834b15ce"
+ },
+ {
"name": "flag_cg",
"unicode": "1F1E8-1F1EC",
"digest": "54498482e2772371e148e05cfb7c5eb55f6a22cd528662abdea10bad47d157da"
},
{
+ "name": "cg",
+ "unicode": "1F1E8-1F1EC",
+ "digest": "54498482e2772371e148e05cfb7c5eb55f6a22cd528662abdea10bad47d157da"
+ },
+ {
"name": "flag_ch",
"unicode": "1F1E8-1F1ED",
"digest": "53d6d35aeeebb0b4b1ad858dc3691e649ac73d30b3be76f96d5fe9605fa99386"
},
{
+ "name": "ch",
+ "unicode": "1F1E8-1F1ED",
+ "digest": "53d6d35aeeebb0b4b1ad858dc3691e649ac73d30b3be76f96d5fe9605fa99386"
+ },
+ {
"name": "flag_ci",
"unicode": "1F1E8-1F1EE",
"digest": "3a173a3058a5c0174dc88750852cafec264e901ce82a6c69db122c8c0ea71a3a"
},
{
+ "name": "ci",
+ "unicode": "1F1E8-1F1EE",
+ "digest": "3a173a3058a5c0174dc88750852cafec264e901ce82a6c69db122c8c0ea71a3a"
+ },
+ {
"name": "flag_ck",
"unicode": "1F1E8-1F1F0",
"digest": "42f395ff53c618b72b8a224cd4343d1a32f5ad82ced56bf590170a5ff0d5134c"
},
{
+ "name": "ck",
+ "unicode": "1F1E8-1F1F0",
+ "digest": "42f395ff53c618b72b8a224cd4343d1a32f5ad82ced56bf590170a5ff0d5134c"
+ },
+ {
"name": "flag_cl",
"unicode": "1F1E8-1F1F1",
"digest": "9d6255feb690596904d800e72d5acdb5cda941c5a741b031ea39a3c7650ac46f"
},
{
+ "name": "chile",
+ "unicode": "1F1E8-1F1F1",
+ "digest": "9d6255feb690596904d800e72d5acdb5cda941c5a741b031ea39a3c7650ac46f"
+ },
+ {
"name": "flag_cm",
"unicode": "1F1E8-1F1F2",
"digest": "ffc99d14e0a8b46a980331090ed9f36f31a87f1b0f8dd8c09007a31c6127c69e"
},
{
+ "name": "cm",
+ "unicode": "1F1E8-1F1F2",
+ "digest": "ffc99d14e0a8b46a980331090ed9f36f31a87f1b0f8dd8c09007a31c6127c69e"
+ },
+ {
"name": "flag_cn",
"unicode": "1F1E8-1F1F3",
"digest": "869a98c52bdc33591f87e2aab6cb4f13e98bb19136250ff25805d0312a8b7c8a"
},
{
+ "name": "cn",
+ "unicode": "1F1E8-1F1F3",
+ "digest": "869a98c52bdc33591f87e2aab6cb4f13e98bb19136250ff25805d0312a8b7c8a"
+ },
+ {
"name": "flag_co",
"unicode": "1F1E8-1F1F4",
"digest": "6aa458440eb2500ad307fea40fd8f1171a1506a6e32af144a4fd51545bb56151"
},
{
+ "name": "co",
+ "unicode": "1F1E8-1F1F4",
+ "digest": "6aa458440eb2500ad307fea40fd8f1171a1506a6e32af144a4fd51545bb56151"
+ },
+ {
"name": "flag_cp",
"unicode": "1F1E8-1F1F5",
"digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
},
{
+ "name": "cp",
+ "unicode": "1F1E8-1F1F5",
+ "digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
+ },
+ {
"name": "flag_cr",
"unicode": "1F1E8-1F1F7",
"digest": "0f3b54d8330c5bb136647547dafc598bda755697cfd6b7d872a2443ba7b5cad4"
},
{
+ "name": "cr",
+ "unicode": "1F1E8-1F1F7",
+ "digest": "0f3b54d8330c5bb136647547dafc598bda755697cfd6b7d872a2443ba7b5cad4"
+ },
+ {
"name": "flag_cu",
"unicode": "1F1E8-1F1FA",
"digest": "69bc973002475bb3d9b54cb0ba9ec9cb85f144c1cf54689da0ee8f414ebb0d83"
},
{
+ "name": "cu",
+ "unicode": "1F1E8-1F1FA",
+ "digest": "69bc973002475bb3d9b54cb0ba9ec9cb85f144c1cf54689da0ee8f414ebb0d83"
+ },
+ {
"name": "flag_cv",
"unicode": "1F1E8-1F1FB",
"digest": "af2e135cf3c1b03a5937c068a75061b5cd332e95902fd0f8dffb2ac2dc89692a"
},
{
+ "name": "cv",
+ "unicode": "1F1E8-1F1FB",
+ "digest": "af2e135cf3c1b03a5937c068a75061b5cd332e95902fd0f8dffb2ac2dc89692a"
+ },
+ {
"name": "flag_cw",
"unicode": "1F1E8-1F1FC",
"digest": "df4b2228a82f766c5c64c13c1388482a68549e59dd843671ee0eb43506e33411"
},
{
+ "name": "cw",
+ "unicode": "1F1E8-1F1FC",
+ "digest": "df4b2228a82f766c5c64c13c1388482a68549e59dd843671ee0eb43506e33411"
+ },
+ {
"name": "flag_cx",
"unicode": "1F1E8-1F1FD",
"digest": "db12e513345a7be53954167d359ede0b3effbfb292508ee4d726123e3a8f83d7"
},
{
+ "name": "cx",
+ "unicode": "1F1E8-1F1FD",
+ "digest": "db12e513345a7be53954167d359ede0b3effbfb292508ee4d726123e3a8f83d7"
+ },
+ {
"name": "flag_cy",
"unicode": "1F1E8-1F1FE",
"digest": "0cea41d4820746e2c6eb408f7ec7419afba9f7396401d92e6c1d77382f721d0b"
},
{
+ "name": "cy",
+ "unicode": "1F1E8-1F1FE",
+ "digest": "0cea41d4820746e2c6eb408f7ec7419afba9f7396401d92e6c1d77382f721d0b"
+ },
+ {
"name": "flag_cz",
"unicode": "1F1E8-1F1FF",
"digest": "a1c2405916963be306f761539123486a2845af53716c9dfe94ad5420e14d36c4"
},
{
+ "name": "cz",
+ "unicode": "1F1E8-1F1FF",
+ "digest": "a1c2405916963be306f761539123486a2845af53716c9dfe94ad5420e14d36c4"
+ },
+ {
"name": "flag_de",
"unicode": "1F1E9-1F1EA",
"digest": "74a80b64437bc4e31bdd7cbb753ecd2d719bf34c506cbac535db83a644174cce"
},
{
+ "name": "de",
+ "unicode": "1F1E9-1F1EA",
+ "digest": "74a80b64437bc4e31bdd7cbb753ecd2d719bf34c506cbac535db83a644174cce"
+ },
+ {
"name": "flag_dg",
"unicode": "1F1E9-1F1EC",
"digest": "13cb5ea872f94a9c3fb579cef417e2d1ed38e8cbe95059576380cacd59bc4b9d"
},
{
+ "name": "dg",
+ "unicode": "1F1E9-1F1EC",
+ "digest": "13cb5ea872f94a9c3fb579cef417e2d1ed38e8cbe95059576380cacd59bc4b9d"
+ },
+ {
"name": "flag_dj",
"unicode": "1F1E9-1F1EF",
"digest": "5b479654c28d3eeb70055c5e25dc46ccaba9eeea7537cc45ca9dbb8186b743b6"
},
{
+ "name": "dj",
+ "unicode": "1F1E9-1F1EF",
+ "digest": "5b479654c28d3eeb70055c5e25dc46ccaba9eeea7537cc45ca9dbb8186b743b6"
+ },
+ {
"name": "flag_dk",
"unicode": "1F1E9-1F1F0",
"digest": "dee7fa9644a9b447417518a353e7edcbb37b2af8bc7d13a6ed71d7210c43ca3c"
},
{
+ "name": "dk",
+ "unicode": "1F1E9-1F1F0",
+ "digest": "dee7fa9644a9b447417518a353e7edcbb37b2af8bc7d13a6ed71d7210c43ca3c"
+ },
+ {
"name": "flag_dm",
"unicode": "1F1E9-1F1F2",
"digest": "2e339190a8a0a238140f42e329f6646af5be75763a787ea268488a2e0440dc4c"
},
{
+ "name": "dm",
+ "unicode": "1F1E9-1F1F2",
+ "digest": "2e339190a8a0a238140f42e329f6646af5be75763a787ea268488a2e0440dc4c"
+ },
+ {
"name": "flag_do",
"unicode": "1F1E9-1F1F4",
"digest": "be5dafcd32d7197a96d37299a91835a8009299452f05a66d91c5fdec17448230"
},
{
+ "name": "do",
+ "unicode": "1F1E9-1F1F4",
+ "digest": "be5dafcd32d7197a96d37299a91835a8009299452f05a66d91c5fdec17448230"
+ },
+ {
"name": "flag_dz",
"unicode": "1F1E9-1F1FF",
"digest": "cf525d56bac45fe689f92d441274fc0ecbed4f95591d2c066598f72b1ee8d618"
},
{
+ "name": "dz",
+ "unicode": "1F1E9-1F1FF",
+ "digest": "cf525d56bac45fe689f92d441274fc0ecbed4f95591d2c066598f72b1ee8d618"
+ },
+ {
"name": "flag_ea",
"unicode": "1F1EA-1F1E6",
"digest": "1acb13950f7c3692f9a36e618d8ec10a73ead5d7fa80fb52b6b2a18e3d456002"
},
{
+ "name": "ea",
+ "unicode": "1F1EA-1F1E6",
+ "digest": "1acb13950f7c3692f9a36e618d8ec10a73ead5d7fa80fb52b6b2a18e3d456002"
+ },
+ {
"name": "flag_ec",
"unicode": "1F1EA-1F1E8",
"digest": "4d9d35450efc6026651ccc2278e70fb90b001ca5e5eecd31361b1e4e23253dbd"
},
{
+ "name": "ec",
+ "unicode": "1F1EA-1F1E8",
+ "digest": "4d9d35450efc6026651ccc2278e70fb90b001ca5e5eecd31361b1e4e23253dbd"
+ },
+ {
"name": "flag_ee",
"unicode": "1F1EA-1F1EA",
"digest": "86ec7b2f618fe71dddec3d5a621b56b878d683780f1e0ad446f965326d42df48"
},
{
+ "name": "ee",
+ "unicode": "1F1EA-1F1EA",
+ "digest": "86ec7b2f618fe71dddec3d5a621b56b878d683780f1e0ad446f965326d42df48"
+ },
+ {
"name": "flag_eg",
"unicode": "1F1EA-1F1EC",
"digest": "f06d36a6fec15af4c1a76de30e8469847dde2728bb5a48956b4e466098b778a4"
},
{
+ "name": "eg",
+ "unicode": "1F1EA-1F1EC",
+ "digest": "f06d36a6fec15af4c1a76de30e8469847dde2728bb5a48956b4e466098b778a4"
+ },
+ {
"name": "flag_eh",
"unicode": "1F1EA-1F1ED",
"digest": "eb63f5b92c62c98dc008dfa7ad8830aa17fa23964f812a28055bd8b6f5960c5b"
},
{
+ "name": "eh",
+ "unicode": "1F1EA-1F1ED",
+ "digest": "eb63f5b92c62c98dc008dfa7ad8830aa17fa23964f812a28055bd8b6f5960c5b"
+ },
+ {
"name": "flag_er",
"unicode": "1F1EA-1F1F7",
"digest": "e901195f7b37b22a6872d36713de0ec176f6424c209e261e5c849ce318c772f6"
},
{
+ "name": "er",
+ "unicode": "1F1EA-1F1F7",
+ "digest": "e901195f7b37b22a6872d36713de0ec176f6424c209e261e5c849ce318c772f6"
+ },
+ {
"name": "flag_es",
"unicode": "1F1EA-1F1F8",
"digest": "27ab5cc6c2e9f26ccdfa632887533eebcd9b514f80cec9e721cf8e5e2544339c"
},
{
+ "name": "es",
+ "unicode": "1F1EA-1F1F8",
+ "digest": "27ab5cc6c2e9f26ccdfa632887533eebcd9b514f80cec9e721cf8e5e2544339c"
+ },
+ {
"name": "flag_et",
"unicode": "1F1EA-1F1F9",
"digest": "6cdb3718c9b3ec713258dd36781db58b7da53f3017445056c1a76233e3b4a7de"
},
{
+ "name": "et",
+ "unicode": "1F1EA-1F1F9",
+ "digest": "6cdb3718c9b3ec713258dd36781db58b7da53f3017445056c1a76233e3b4a7de"
+ },
+ {
"name": "flag_eu",
"unicode": "1F1EA-1F1FA",
"digest": "363f60e8a747166d5cec8d70bfdf266411eec2ff07933b6187975075caadfd74"
},
{
+ "name": "eu",
+ "unicode": "1F1EA-1F1FA",
+ "digest": "363f60e8a747166d5cec8d70bfdf266411eec2ff07933b6187975075caadfd74"
+ },
+ {
"name": "flag_fi",
"unicode": "1F1EB-1F1EE",
"digest": "1a1959cb551a0e8bdaee8c04657fb7387a4d83173f7759f89468da12e1818a9e"
},
{
+ "name": "fi",
+ "unicode": "1F1EB-1F1EE",
+ "digest": "1a1959cb551a0e8bdaee8c04657fb7387a4d83173f7759f89468da12e1818a9e"
+ },
+ {
"name": "flag_fj",
"unicode": "1F1EB-1F1EF",
"digest": "f26dc36ea9c1f32d9bb54874ea384e7118b6e2585be69245fdd73acd8304ae78"
},
{
+ "name": "fj",
+ "unicode": "1F1EB-1F1EF",
+ "digest": "f26dc36ea9c1f32d9bb54874ea384e7118b6e2585be69245fdd73acd8304ae78"
+ },
+ {
"name": "flag_fk",
"unicode": "1F1EB-1F1F0",
"digest": "0479e233499b704f91a9b13d083e66296efe2f28ed917ab1496b223bfb09adb8"
},
{
+ "name": "fk",
+ "unicode": "1F1EB-1F1F0",
+ "digest": "0479e233499b704f91a9b13d083e66296efe2f28ed917ab1496b223bfb09adb8"
+ },
+ {
"name": "flag_fm",
"unicode": "1F1EB-1F1F2",
"digest": "142ea7b4b4a7004329925b495da43ab82351cbaac383c8da6e614b39ba58d05e"
},
{
+ "name": "fm",
+ "unicode": "1F1EB-1F1F2",
+ "digest": "142ea7b4b4a7004329925b495da43ab82351cbaac383c8da6e614b39ba58d05e"
+ },
+ {
"name": "flag_fo",
"unicode": "1F1EB-1F1F4",
"digest": "f1c800d4f4d39e2aead9a11ed500f16108d6bc48bd24bd2a1af7b966d8e76752"
},
{
+ "name": "fo",
+ "unicode": "1F1EB-1F1F4",
+ "digest": "f1c800d4f4d39e2aead9a11ed500f16108d6bc48bd24bd2a1af7b966d8e76752"
+ },
+ {
"name": "flag_fr",
"unicode": "1F1EB-1F1F7",
"digest": "6f52f36b5199c65ab1cad13ff4e77d2d8b48a8ff79b92166976674ffdc7829ee"
},
{
+ "name": "fr",
+ "unicode": "1F1EB-1F1F7",
+ "digest": "6f52f36b5199c65ab1cad13ff4e77d2d8b48a8ff79b92166976674ffdc7829ee"
+ },
+ {
"name": "flag_ga",
"unicode": "1F1EC-1F1E6",
"digest": "50a0d5a07466e419b74a4d532738f7958de9baa37df6191be4f3755dccc3b326"
},
{
+ "name": "ga",
+ "unicode": "1F1EC-1F1E6",
+ "digest": "50a0d5a07466e419b74a4d532738f7958de9baa37df6191be4f3755dccc3b326"
+ },
+ {
"name": "flag_gb",
"unicode": "1F1EC-1F1E7",
"digest": "220f7da6d5a231b766c79f2e1b7d3fdb74ec0c0c17558cc00a8a8ccdf2afc2e0"
},
{
+ "name": "gb",
+ "unicode": "1F1EC-1F1E7",
+ "digest": "220f7da6d5a231b766c79f2e1b7d3fdb74ec0c0c17558cc00a8a8ccdf2afc2e0"
+ },
+ {
"name": "flag_gd",
"unicode": "1F1EC-1F1E9",
"digest": "3e162b0d13f4ceea7f663b1d425f13863d104e80df75a640f526e276bcd04081"
},
{
+ "name": "gd",
+ "unicode": "1F1EC-1F1E9",
+ "digest": "3e162b0d13f4ceea7f663b1d425f13863d104e80df75a640f526e276bcd04081"
+ },
+ {
"name": "flag_ge",
"unicode": "1F1EC-1F1EA",
"digest": "35897f8254675d2efe9e3070c88af9ef214f08440e6ee75ebe81d28cdb57ea2b"
},
{
+ "name": "ge",
+ "unicode": "1F1EC-1F1EA",
+ "digest": "35897f8254675d2efe9e3070c88af9ef214f08440e6ee75ebe81d28cdb57ea2b"
+ },
+ {
"name": "flag_gf",
"unicode": "1F1EC-1F1EB",
"digest": "3a34df321635f71a0f2cc4e1eda58d85c29230c77456362345196351bf56533d"
},
{
+ "name": "gf",
+ "unicode": "1F1EC-1F1EB",
+ "digest": "3a34df321635f71a0f2cc4e1eda58d85c29230c77456362345196351bf56533d"
+ },
+ {
"name": "flag_gg",
"unicode": "1F1EC-1F1EC",
"digest": "c972f8d190b4e9ca8890df41503d202ffd73981833d3f3750f563302167bcd66"
},
{
+ "name": "gg",
+ "unicode": "1F1EC-1F1EC",
+ "digest": "c972f8d190b4e9ca8890df41503d202ffd73981833d3f3750f563302167bcd66"
+ },
+ {
"name": "flag_gh",
"unicode": "1F1EC-1F1ED",
"digest": "9c3d3569bd411389fa0af7c6938d4325cedeb9c0e8f059dc1d5a74c6b8d6d01b"
},
{
+ "name": "gh",
+ "unicode": "1F1EC-1F1ED",
+ "digest": "9c3d3569bd411389fa0af7c6938d4325cedeb9c0e8f059dc1d5a74c6b8d6d01b"
+ },
+ {
"name": "flag_gi",
"unicode": "1F1EC-1F1EE",
"digest": "ede638bc6fedc30a01821025d87ec19297500da9c04a7a155984fca186118649"
},
{
+ "name": "gi",
+ "unicode": "1F1EC-1F1EE",
+ "digest": "ede638bc6fedc30a01821025d87ec19297500da9c04a7a155984fca186118649"
+ },
+ {
"name": "flag_gl",
"unicode": "1F1EC-1F1F1",
"digest": "a2ce3371eff1da8331671925f707232aa593ac7400d59555c9ca689729ce24ec"
},
{
+ "name": "gl",
+ "unicode": "1F1EC-1F1F1",
+ "digest": "a2ce3371eff1da8331671925f707232aa593ac7400d59555c9ca689729ce24ec"
+ },
+ {
"name": "flag_gm",
"unicode": "1F1EC-1F1F2",
"digest": "932bf6eb75ddd4278268dd2f09d8fffcfef89f8fd6b6e86a08a414cd3ceec94d"
},
{
+ "name": "gm",
+ "unicode": "1F1EC-1F1F2",
+ "digest": "932bf6eb75ddd4278268dd2f09d8fffcfef89f8fd6b6e86a08a414cd3ceec94d"
+ },
+ {
"name": "flag_gn",
"unicode": "1F1EC-1F1F3",
"digest": "ebf543713895adaa09d64897f24bd461191191b8fcbbcede52bdaf4bd2dc67a8"
},
{
+ "name": "gn",
+ "unicode": "1F1EC-1F1F3",
+ "digest": "ebf543713895adaa09d64897f24bd461191191b8fcbbcede52bdaf4bd2dc67a8"
+ },
+ {
"name": "flag_gp",
"unicode": "1F1EC-1F1F5",
"digest": "2e6c48d80c571b34f31fa9b3622dcc51e1707c0118e991e9c177742ff02a8a96"
},
{
+ "name": "gp",
+ "unicode": "1F1EC-1F1F5",
+ "digest": "2e6c48d80c571b34f31fa9b3622dcc51e1707c0118e991e9c177742ff02a8a96"
+ },
+ {
"name": "flag_gq",
"unicode": "1F1EC-1F1F6",
"digest": "b0f5810180d12fc48faf75e73f882dc59072d7bf957f8455bf7e1e336539dc41"
},
{
+ "name": "gq",
+ "unicode": "1F1EC-1F1F6",
+ "digest": "b0f5810180d12fc48faf75e73f882dc59072d7bf957f8455bf7e1e336539dc41"
+ },
+ {
"name": "flag_gr",
"unicode": "1F1EC-1F1F7",
"digest": "8d60d6f8910f5179d851dbea0798b56a492c6be85f3d55e1a1126cd1d6663a3b"
},
{
+ "name": "gr",
+ "unicode": "1F1EC-1F1F7",
+ "digest": "8d60d6f8910f5179d851dbea0798b56a492c6be85f3d55e1a1126cd1d6663a3b"
+ },
+ {
"name": "flag_gs",
"unicode": "1F1EC-1F1F8",
"digest": "7b07915af0e2364ebc386a162d44846f3a7986fdd24e20ad2bc56d64a103fe9c"
},
{
+ "name": "gs",
+ "unicode": "1F1EC-1F1F8",
+ "digest": "7b07915af0e2364ebc386a162d44846f3a7986fdd24e20ad2bc56d64a103fe9c"
+ },
+ {
"name": "flag_gt",
"unicode": "1F1EC-1F1F9",
"digest": "0c78108ede45bf34917b409a0867f5ec8253c74b694beda083f3e8d04d7a10d8"
},
{
+ "name": "gt",
+ "unicode": "1F1EC-1F1F9",
+ "digest": "0c78108ede45bf34917b409a0867f5ec8253c74b694beda083f3e8d04d7a10d8"
+ },
+ {
"name": "flag_gu",
"unicode": "1F1EC-1F1FA",
"digest": "909f1bc98fa1507adb787eb3875503b21ea937d6ae8bb152153916c2da5e13bb"
},
{
+ "name": "gu",
+ "unicode": "1F1EC-1F1FA",
+ "digest": "909f1bc98fa1507adb787eb3875503b21ea937d6ae8bb152153916c2da5e13bb"
+ },
+ {
"name": "flag_gw",
"unicode": "1F1EC-1F1FC",
"digest": "f5f34410c7b22d5ed9994b47d0e7a9d9a6a1f05c4d3142f7fef3e4409725f5e6"
},
{
+ "name": "gw",
+ "unicode": "1F1EC-1F1FC",
+ "digest": "f5f34410c7b22d5ed9994b47d0e7a9d9a6a1f05c4d3142f7fef3e4409725f5e6"
+ },
+ {
"name": "flag_gy",
"unicode": "1F1EC-1F1FE",
"digest": "4939cf52ab34a924a31032b42668960a2c7d8d4f998b16b065c247110df334be"
},
{
+ "name": "gy",
+ "unicode": "1F1EC-1F1FE",
+ "digest": "4939cf52ab34a924a31032b42668960a2c7d8d4f998b16b065c247110df334be"
+ },
+ {
"name": "flag_hk",
"unicode": "1F1ED-1F1F0",
"digest": "bde0916df6d62f6b1cf8f85a8a39526c97fc6ef6fedb0b0cae2adb127a08eafe"
},
{
+ "name": "hk",
+ "unicode": "1F1ED-1F1F0",
+ "digest": "bde0916df6d62f6b1cf8f85a8a39526c97fc6ef6fedb0b0cae2adb127a08eafe"
+ },
+ {
"name": "flag_hm",
"unicode": "1F1ED-1F1F2",
"digest": "603e6c9bff9a0dc941970a313fe98fbf53ff5a57028f1a2766420be4211711cc"
},
{
+ "name": "hm",
+ "unicode": "1F1ED-1F1F2",
+ "digest": "603e6c9bff9a0dc941970a313fe98fbf53ff5a57028f1a2766420be4211711cc"
+ },
+ {
"name": "flag_hn",
"unicode": "1F1ED-1F1F3",
"digest": "2953ad0909bc32c02615f6ad5a4e5f331ba794a41632b1f0fc366e1c640cc2b9"
},
{
+ "name": "hn",
+ "unicode": "1F1ED-1F1F3",
+ "digest": "2953ad0909bc32c02615f6ad5a4e5f331ba794a41632b1f0fc366e1c640cc2b9"
+ },
+ {
"name": "flag_hr",
"unicode": "1F1ED-1F1F7",
"digest": "41c9ffc4f0faaa2d77e5cffb781329e7d2489ce879bd8eb9c503621e834abc50"
},
{
+ "name": "hr",
+ "unicode": "1F1ED-1F1F7",
+ "digest": "41c9ffc4f0faaa2d77e5cffb781329e7d2489ce879bd8eb9c503621e834abc50"
+ },
+ {
"name": "flag_ht",
"unicode": "1F1ED-1F1F9",
"digest": "6a56c3d71b4f858e1774aa2134a9f5584087fec968e9ee8bb1046d2ec93bf059"
},
{
+ "name": "ht",
+ "unicode": "1F1ED-1F1F9",
+ "digest": "6a56c3d71b4f858e1774aa2134a9f5584087fec968e9ee8bb1046d2ec93bf059"
+ },
+ {
"name": "flag_hu",
"unicode": "1F1ED-1F1FA",
"digest": "72f5809818d4cab8c0cee73df7f67b820fb8471eea4199911a5917ac099795e8"
},
{
+ "name": "hu",
+ "unicode": "1F1ED-1F1FA",
+ "digest": "72f5809818d4cab8c0cee73df7f67b820fb8471eea4199911a5917ac099795e8"
+ },
+ {
"name": "flag_ic",
"unicode": "1F1EE-1F1E8",
"digest": "7e2a7667fcd05f927af47e64c5790c104a9956dd9f1a45f03cb0fdcc85d866d3"
},
{
+ "name": "ic",
+ "unicode": "1F1EE-1F1E8",
+ "digest": "7e2a7667fcd05f927af47e64c5790c104a9956dd9f1a45f03cb0fdcc85d866d3"
+ },
+ {
"name": "flag_id",
"unicode": "1F1EE-1F1E9",
"digest": "4721f616fae2e443e52f1e9cc96e4835bddca16a2d75d7d5afea57cdee866b7f"
},
{
+ "name": "indonesia",
+ "unicode": "1F1EE-1F1E9",
+ "digest": "4721f616fae2e443e52f1e9cc96e4835bddca16a2d75d7d5afea57cdee866b7f"
+ },
+ {
"name": "flag_ie",
"unicode": "1F1EE-1F1EA",
"digest": "84b19833e6c9fb43187f8a28d85045a3df58816f20a07edab90474323174b1f3"
},
{
+ "name": "ie",
+ "unicode": "1F1EE-1F1EA",
+ "digest": "84b19833e6c9fb43187f8a28d85045a3df58816f20a07edab90474323174b1f3"
+ },
+ {
"name": "flag_il",
"unicode": "1F1EE-1F1F1",
"digest": "c99d4bd8c2541cf3a7392c4faf4477d96bc47065dd1423b9e06450483e69b34f"
},
{
+ "name": "il",
+ "unicode": "1F1EE-1F1F1",
+ "digest": "c99d4bd8c2541cf3a7392c4faf4477d96bc47065dd1423b9e06450483e69b34f"
+ },
+ {
"name": "flag_im",
"unicode": "1F1EE-1F1F2",
"digest": "5eeb12c0315b527ce61649a38b64d76af726a73b2d381d1a1ddd1366bafb1bfc"
},
{
+ "name": "im",
+ "unicode": "1F1EE-1F1F2",
+ "digest": "5eeb12c0315b527ce61649a38b64d76af726a73b2d381d1a1ddd1366bafb1bfc"
+ },
+ {
"name": "flag_in",
"unicode": "1F1EE-1F1F3",
"digest": "ecc3cfcff3368fe0875a51a8be9f4dfd449a187e5beb41a2b34241736247f73b"
},
{
+ "name": "in",
+ "unicode": "1F1EE-1F1F3",
+ "digest": "ecc3cfcff3368fe0875a51a8be9f4dfd449a187e5beb41a2b34241736247f73b"
+ },
+ {
"name": "flag_io",
"unicode": "1F1EE-1F1F4",
"digest": "26243d60e04ba3bc9eb8f008bfc77b2a64bcf1a3d0073eb0449a8c8121618c9c"
},
{
+ "name": "io",
+ "unicode": "1F1EE-1F1F4",
+ "digest": "26243d60e04ba3bc9eb8f008bfc77b2a64bcf1a3d0073eb0449a8c8121618c9c"
+ },
+ {
"name": "flag_iq",
"unicode": "1F1EE-1F1F6",
"digest": "a1fb5e59575081920b3be5290f654d57a9be099deb56d4ed69eba81a2b531cb3"
},
{
+ "name": "iq",
+ "unicode": "1F1EE-1F1F6",
+ "digest": "a1fb5e59575081920b3be5290f654d57a9be099deb56d4ed69eba81a2b531cb3"
+ },
+ {
"name": "flag_ir",
"unicode": "1F1EE-1F1F7",
"digest": "ab89488b934af1d4bdae7ed16dfc74fffe658bb8e95d5161b48cdd06de44ae85"
},
{
+ "name": "ir",
+ "unicode": "1F1EE-1F1F7",
+ "digest": "ab89488b934af1d4bdae7ed16dfc74fffe658bb8e95d5161b48cdd06de44ae85"
+ },
+ {
"name": "flag_is",
"unicode": "1F1EE-1F1F8",
"digest": "55db1fc9e6c56d4c9bcb9a46e5e4300cf2a0c32fa91dc24b487a1d56c8097268"
},
{
+ "name": "is",
+ "unicode": "1F1EE-1F1F8",
+ "digest": "55db1fc9e6c56d4c9bcb9a46e5e4300cf2a0c32fa91dc24b487a1d56c8097268"
+ },
+ {
"name": "flag_it",
"unicode": "1F1EE-1F1F9",
"digest": "36fc993fb00ab607578a4d0e573e988e17b9459a68a000a48de905a8238589d0"
},
{
+ "name": "it",
+ "unicode": "1F1EE-1F1F9",
+ "digest": "36fc993fb00ab607578a4d0e573e988e17b9459a68a000a48de905a8238589d0"
+ },
+ {
"name": "flag_je",
"unicode": "1F1EF-1F1EA",
"digest": "c608dbfd1259330e2f8c40dc5d12ffd0489396f4fc5f3ca57bcb2f0d9d05c20c"
},
{
+ "name": "je",
+ "unicode": "1F1EF-1F1EA",
+ "digest": "c608dbfd1259330e2f8c40dc5d12ffd0489396f4fc5f3ca57bcb2f0d9d05c20c"
+ },
+ {
"name": "flag_jm",
"unicode": "1F1EF-1F1F2",
"digest": "a8224b68b2d324f848d75e4376875ef76a8174e6ba32790d9ca622fe1eabfd5f"
},
{
+ "name": "jm",
+ "unicode": "1F1EF-1F1F2",
+ "digest": "a8224b68b2d324f848d75e4376875ef76a8174e6ba32790d9ca622fe1eabfd5f"
+ },
+ {
"name": "flag_jo",
"unicode": "1F1EF-1F1F4",
"digest": "2403563dc2ab4ed0e7e3a0761cc09f96801550bba6b177b54d651d8804ad987d"
},
{
+ "name": "jo",
+ "unicode": "1F1EF-1F1F4",
+ "digest": "2403563dc2ab4ed0e7e3a0761cc09f96801550bba6b177b54d651d8804ad987d"
+ },
+ {
"name": "flag_jp",
"unicode": "1F1EF-1F1F5",
"digest": "aea8eebd0a0139818cb7629d9c9a8e55160b458eb8ffeee2f36c5cff4b507fd3"
},
{
+ "name": "jp",
+ "unicode": "1F1EF-1F1F5",
+ "digest": "aea8eebd0a0139818cb7629d9c9a8e55160b458eb8ffeee2f36c5cff4b507fd3"
+ },
+ {
"name": "flag_ke",
"unicode": "1F1F0-1F1EA",
"digest": "9c8365f74858743bcdce4a9cf6a6f4110faf2dc6433e5dc7d98c24bb3b32a36d"
},
{
+ "name": "ke",
+ "unicode": "1F1F0-1F1EA",
+ "digest": "9c8365f74858743bcdce4a9cf6a6f4110faf2dc6433e5dc7d98c24bb3b32a36d"
+ },
+ {
"name": "flag_kg",
"unicode": "1F1F0-1F1EC",
"digest": "0c72bdb1d64b1e3be3d9516a50655a6162d8501851d2cf2fadb8c6ef7740df4e"
},
{
+ "name": "kg",
+ "unicode": "1F1F0-1F1EC",
+ "digest": "0c72bdb1d64b1e3be3d9516a50655a6162d8501851d2cf2fadb8c6ef7740df4e"
+ },
+ {
"name": "flag_kh",
"unicode": "1F1F0-1F1ED",
"digest": "49e41e488732d789e395091e144cd6215c6818ba2073e5e22ea21203a737d03c"
},
{
+ "name": "kh",
+ "unicode": "1F1F0-1F1ED",
+ "digest": "49e41e488732d789e395091e144cd6215c6818ba2073e5e22ea21203a737d03c"
+ },
+ {
"name": "flag_ki",
"unicode": "1F1F0-1F1EE",
"digest": "9d7f168adbcf5f4cfe28470addfdb0a8b231438d593edb70f633981bfa4c7638"
},
{
+ "name": "ki",
+ "unicode": "1F1F0-1F1EE",
+ "digest": "9d7f168adbcf5f4cfe28470addfdb0a8b231438d593edb70f633981bfa4c7638"
+ },
+ {
"name": "flag_km",
"unicode": "1F1F0-1F1F2",
"digest": "9318c28957fa7a19eba5ec452c1cbce01a5a83d41d29d081614d3abb0585d478"
},
{
+ "name": "km",
+ "unicode": "1F1F0-1F1F2",
+ "digest": "9318c28957fa7a19eba5ec452c1cbce01a5a83d41d29d081614d3abb0585d478"
+ },
+ {
"name": "flag_kn",
"unicode": "1F1F0-1F1F3",
"digest": "eac7e7d0f023dee5c0c8559bc2c9a96273adda54ce47598025120b30d8d6ebc1"
},
{
+ "name": "kn",
+ "unicode": "1F1F0-1F1F3",
+ "digest": "eac7e7d0f023dee5c0c8559bc2c9a96273adda54ce47598025120b30d8d6ebc1"
+ },
+ {
"name": "flag_kp",
"unicode": "1F1F0-1F1F5",
"digest": "d4d53db6f8363174de6db864c056267ba8a7d7e87b5527f2f42bb9b8ac3f362b"
},
{
+ "name": "kp",
+ "unicode": "1F1F0-1F1F5",
+ "digest": "d4d53db6f8363174de6db864c056267ba8a7d7e87b5527f2f42bb9b8ac3f362b"
+ },
+ {
"name": "flag_kr",
"unicode": "1F1F0-1F1F7",
"digest": "5c7e61ab4a2aae70cbe51f0ca4718516002bc943b35d870bd853a0c98c4e0ed5"
},
{
+ "name": "kr",
+ "unicode": "1F1F0-1F1F7",
+ "digest": "5c7e61ab4a2aae70cbe51f0ca4718516002bc943b35d870bd853a0c98c4e0ed5"
+ },
+ {
"name": "flag_kw",
"unicode": "1F1F0-1F1FC",
"digest": "5d229cd99d25f4285bd30d98cfcc3cd8346648897476e2905a1811ceeef48d37"
},
{
+ "name": "kw",
+ "unicode": "1F1F0-1F1FC",
+ "digest": "5d229cd99d25f4285bd30d98cfcc3cd8346648897476e2905a1811ceeef48d37"
+ },
+ {
"name": "flag_ky",
"unicode": "1F1F0-1F1FE",
"digest": "9ce3d8dfc273d3a400960876c434b702f93df92c6c00682dbed2ec8e3966d8a8"
},
{
+ "name": "ky",
+ "unicode": "1F1F0-1F1FE",
+ "digest": "9ce3d8dfc273d3a400960876c434b702f93df92c6c00682dbed2ec8e3966d8a8"
+ },
+ {
"name": "flag_kz",
"unicode": "1F1F0-1F1FF",
"digest": "a6f0be0a767fa4824495d568d9fc2bd8d4c1a26f363873d3b65362e9383e2a50"
},
{
+ "name": "kz",
+ "unicode": "1F1F0-1F1FF",
+ "digest": "a6f0be0a767fa4824495d568d9fc2bd8d4c1a26f363873d3b65362e9383e2a50"
+ },
+ {
"name": "flag_la",
"unicode": "1F1F1-1F1E6",
"digest": "ab2ae96da87f7b53ab212f8dcd897a591cff9ea6666270097a8e739ee0b8f8cb"
},
{
+ "name": "la",
+ "unicode": "1F1F1-1F1E6",
+ "digest": "ab2ae96da87f7b53ab212f8dcd897a591cff9ea6666270097a8e739ee0b8f8cb"
+ },
+ {
"name": "flag_lb",
"unicode": "1F1F1-1F1E7",
"digest": "0c3fcab22e9fae1c78658290aff97de785d0b6adb5e3702d00073ce774b7ed54"
},
{
+ "name": "lb",
+ "unicode": "1F1F1-1F1E7",
+ "digest": "0c3fcab22e9fae1c78658290aff97de785d0b6adb5e3702d00073ce774b7ed54"
+ },
+ {
"name": "flag_lc",
"unicode": "1F1F1-1F1E8",
"digest": "e154b0b3a1635a36e0d9ad518c0ea12259320e5f1ebbda982248486492065d28"
},
{
+ "name": "lc",
+ "unicode": "1F1F1-1F1E8",
+ "digest": "e154b0b3a1635a36e0d9ad518c0ea12259320e5f1ebbda982248486492065d28"
+ },
+ {
"name": "flag_li",
"unicode": "1F1F1-1F1EE",
"digest": "bbc393a89e73cc8c29a0a9297428d07aa1d4717ea9b7d4dd9d69f21ac7d0605d"
},
{
+ "name": "li",
+ "unicode": "1F1F1-1F1EE",
+ "digest": "bbc393a89e73cc8c29a0a9297428d07aa1d4717ea9b7d4dd9d69f21ac7d0605d"
+ },
+ {
"name": "flag_lk",
"unicode": "1F1F1-1F1F0",
"digest": "376bd501d113a844971ca1006ab31aa086cd55d74842ea5f3dedaba997b58693"
},
{
+ "name": "lk",
+ "unicode": "1F1F1-1F1F0",
+ "digest": "376bd501d113a844971ca1006ab31aa086cd55d74842ea5f3dedaba997b58693"
+ },
+ {
"name": "flag_lr",
"unicode": "1F1F1-1F1F7",
"digest": "9a6ebe1c9d9a53079ee77292a5ad0965f96409b0417f92876a1c3bd463d6a9bc"
},
{
+ "name": "lr",
+ "unicode": "1F1F1-1F1F7",
+ "digest": "9a6ebe1c9d9a53079ee77292a5ad0965f96409b0417f92876a1c3bd463d6a9bc"
+ },
+ {
"name": "flag_ls",
"unicode": "1F1F1-1F1F8",
"digest": "e2f4b05414f6e0c3d629a92b0534d4145475f0214a83a62c902fe0884c833c89"
},
{
+ "name": "ls",
+ "unicode": "1F1F1-1F1F8",
+ "digest": "e2f4b05414f6e0c3d629a92b0534d4145475f0214a83a62c902fe0884c833c89"
+ },
+ {
"name": "flag_lt",
"unicode": "1F1F1-1F1F9",
"digest": "d5e2f8b2ffa820a33ea6d612fccd61e32467d25154342f5be134d3520e48387f"
},
{
+ "name": "lt",
+ "unicode": "1F1F1-1F1F9",
+ "digest": "d5e2f8b2ffa820a33ea6d612fccd61e32467d25154342f5be134d3520e48387f"
+ },
+ {
"name": "flag_lu",
"unicode": "1F1F1-1F1FA",
"digest": "f43277103292195b51981d08e2dde68eab660a65c7875f510e09a8b2370f1b5c"
},
{
+ "name": "lu",
+ "unicode": "1F1F1-1F1FA",
+ "digest": "f43277103292195b51981d08e2dde68eab660a65c7875f510e09a8b2370f1b5c"
+ },
+ {
"name": "flag_lv",
"unicode": "1F1F1-1F1FB",
"digest": "e1288ac5c80d6e9d577d652e34be247ca39bf9d3d7cfc8a6cae13c1f9ac9dc47"
},
{
+ "name": "lv",
+ "unicode": "1F1F1-1F1FB",
+ "digest": "e1288ac5c80d6e9d577d652e34be247ca39bf9d3d7cfc8a6cae13c1f9ac9dc47"
+ },
+ {
"name": "flag_ly",
"unicode": "1F1F1-1F1FE",
"digest": "5122294b769a174e3b6e3d238bb846b3e760929f5bb3c1a708d8a429f3f32f68"
},
{
+ "name": "ly",
+ "unicode": "1F1F1-1F1FE",
+ "digest": "5122294b769a174e3b6e3d238bb846b3e760929f5bb3c1a708d8a429f3f32f68"
+ },
+ {
"name": "flag_ma",
"unicode": "1F1F2-1F1E6",
"digest": "615a6447ff284de7689b4fd7b04fdda308f65dbbec958cfb96d2977514981d16"
},
{
+ "name": "ma",
+ "unicode": "1F1F2-1F1E6",
+ "digest": "615a6447ff284de7689b4fd7b04fdda308f65dbbec958cfb96d2977514981d16"
+ },
+ {
"name": "flag_mc",
"unicode": "1F1F2-1F1E8",
"digest": "08b48b28938acbfc0fbc15c25ee14dbad7164c5165d03df2eee370755ee7b4cf"
},
{
+ "name": "mc",
+ "unicode": "1F1F2-1F1E8",
+ "digest": "08b48b28938acbfc0fbc15c25ee14dbad7164c5165d03df2eee370755ee7b4cf"
+ },
+ {
"name": "flag_md",
"unicode": "1F1F2-1F1E9",
"digest": "93d61de68f821e1e08b30e63d91e8b4a657766475128538894cf9da9a3b4e3c0"
},
{
+ "name": "md",
+ "unicode": "1F1F2-1F1E9",
+ "digest": "93d61de68f821e1e08b30e63d91e8b4a657766475128538894cf9da9a3b4e3c0"
+ },
+ {
"name": "flag_me",
"unicode": "1F1F2-1F1EA",
"digest": "ee55c0eb78241aec2baf1822a47fa46d63209ceae3db7617ae886b823ae229ff"
},
{
+ "name": "me",
+ "unicode": "1F1F2-1F1EA",
+ "digest": "ee55c0eb78241aec2baf1822a47fa46d63209ceae3db7617ae886b823ae229ff"
+ },
+ {
"name": "flag_mf",
"unicode": "1F1F2-1F1EB",
"digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
},
{
+ "name": "mf",
+ "unicode": "1F1F2-1F1EB",
+ "digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
+ },
+ {
"name": "flag_mg",
"unicode": "1F1F2-1F1EC",
"digest": "86ec8140e2c4854f52cff74757baf0cbb75a4aacca8be6af8c8f9c939a7b866c"
},
{
+ "name": "mg",
+ "unicode": "1F1F2-1F1EC",
+ "digest": "86ec8140e2c4854f52cff74757baf0cbb75a4aacca8be6af8c8f9c939a7b866c"
+ },
+ {
"name": "flag_mh",
"unicode": "1F1F2-1F1ED",
"digest": "8311ea3422c9d5e94b55e19b03bedd6fe6e2a191b7657e15ac75a48932958a5b"
},
{
+ "name": "mh",
+ "unicode": "1F1F2-1F1ED",
+ "digest": "8311ea3422c9d5e94b55e19b03bedd6fe6e2a191b7657e15ac75a48932958a5b"
+ },
+ {
"name": "flag_mk",
"unicode": "1F1F2-1F1F0",
"digest": "5c6f504f88c5a875c06ac8b26fa6e81a9d79c42a1c7d1fad9a5d4c8ad06ca502"
},
{
+ "name": "mk",
+ "unicode": "1F1F2-1F1F0",
+ "digest": "5c6f504f88c5a875c06ac8b26fa6e81a9d79c42a1c7d1fad9a5d4c8ad06ca502"
+ },
+ {
"name": "flag_ml",
"unicode": "1F1F2-1F1F1",
"digest": "d08a4973db40cf28e58ca3c80e8bd4e50d68ba1080b31917aeefdb0e210b5c50"
},
{
+ "name": "ml",
+ "unicode": "1F1F2-1F1F1",
+ "digest": "d08a4973db40cf28e58ca3c80e8bd4e50d68ba1080b31917aeefdb0e210b5c50"
+ },
+ {
"name": "flag_mm",
"unicode": "1F1F2-1F1F2",
"digest": "5e95089514ca09bb93afb481b317477c9d053adcf450e0b711d78ed1078c7470"
},
{
+ "name": "mm",
+ "unicode": "1F1F2-1F1F2",
+ "digest": "5e95089514ca09bb93afb481b317477c9d053adcf450e0b711d78ed1078c7470"
+ },
+ {
"name": "flag_mn",
"unicode": "1F1F2-1F1F3",
"digest": "7a0ca72715dd2a36eeeed2f8c888497cb752f0000af8f07d6930743caf6e4273"
},
{
+ "name": "mn",
+ "unicode": "1F1F2-1F1F3",
+ "digest": "7a0ca72715dd2a36eeeed2f8c888497cb752f0000af8f07d6930743caf6e4273"
+ },
+ {
"name": "flag_mo",
"unicode": "1F1F2-1F1F4",
"digest": "d2c7c2191bc1bc83d85f2270968cb4de5cf26a11f70e166a8b32c108287ef729"
},
{
+ "name": "mo",
+ "unicode": "1F1F2-1F1F4",
+ "digest": "d2c7c2191bc1bc83d85f2270968cb4de5cf26a11f70e166a8b32c108287ef729"
+ },
+ {
"name": "flag_mp",
"unicode": "1F1F2-1F1F5",
"digest": "89ad06121fd7981338fe188464491bea371f85125bfb4fc01fb5cad606613b1e"
},
{
+ "name": "mp",
+ "unicode": "1F1F2-1F1F5",
+ "digest": "89ad06121fd7981338fe188464491bea371f85125bfb4fc01fb5cad606613b1e"
+ },
+ {
"name": "flag_mq",
"unicode": "1F1F2-1F1F6",
"digest": "98176f3af823b26a3657a17c5073ee22367898b40bd3973de76329aa87ca5a2e"
},
{
+ "name": "mq",
+ "unicode": "1F1F2-1F1F6",
+ "digest": "98176f3af823b26a3657a17c5073ee22367898b40bd3973de76329aa87ca5a2e"
+ },
+ {
"name": "flag_mr",
"unicode": "1F1F2-1F1F7",
"digest": "cc3e705ad84f83fe2d544385c39564743024dab26595d62469b35fdb791f6015"
},
{
+ "name": "mr",
+ "unicode": "1F1F2-1F1F7",
+ "digest": "cc3e705ad84f83fe2d544385c39564743024dab26595d62469b35fdb791f6015"
+ },
+ {
"name": "flag_ms",
"unicode": "1F1F2-1F1F8",
"digest": "465e3d5700b557f2589bd6e34a0c6b12c634a6ed4dcfbee3c1c841c5de3413f0"
},
{
+ "name": "ms",
+ "unicode": "1F1F2-1F1F8",
+ "digest": "465e3d5700b557f2589bd6e34a0c6b12c634a6ed4dcfbee3c1c841c5de3413f0"
+ },
+ {
"name": "flag_mt",
"unicode": "1F1F2-1F1F9",
"digest": "e610ba22d8d8ad750ed10dff8e1b4d89bc34f066c3424bfa77dbdc1a5d79743a"
},
{
+ "name": "mt",
+ "unicode": "1F1F2-1F1F9",
+ "digest": "e610ba22d8d8ad750ed10dff8e1b4d89bc34f066c3424bfa77dbdc1a5d79743a"
+ },
+ {
"name": "flag_mu",
"unicode": "1F1F2-1F1FA",
"digest": "3daf015d3b95218677dafbb282b7804686aa68875a6bd1d70c165b7b149e19cb"
},
{
+ "name": "mu",
+ "unicode": "1F1F2-1F1FA",
+ "digest": "3daf015d3b95218677dafbb282b7804686aa68875a6bd1d70c165b7b149e19cb"
+ },
+ {
"name": "flag_mv",
"unicode": "1F1F2-1F1FB",
"digest": "d30e4bfd04f08177de92f3c175600aaafa89b9668bbe2b83f35f07a74382065c"
},
{
+ "name": "mv",
+ "unicode": "1F1F2-1F1FB",
+ "digest": "d30e4bfd04f08177de92f3c175600aaafa89b9668bbe2b83f35f07a74382065c"
+ },
+ {
"name": "flag_mw",
"unicode": "1F1F2-1F1FC",
"digest": "f364b1c8bfda3f86b5e26422eedc571ba11e312dcc634197631a6840cb22aede"
},
{
+ "name": "mw",
+ "unicode": "1F1F2-1F1FC",
+ "digest": "f364b1c8bfda3f86b5e26422eedc571ba11e312dcc634197631a6840cb22aede"
+ },
+ {
"name": "flag_mx",
"unicode": "1F1F2-1F1FD",
"digest": "eafb02ec0be9cefab7cef7c426c7d860d98e4947f4da04054154dc86d8f487c4"
},
{
+ "name": "mx",
+ "unicode": "1F1F2-1F1FD",
+ "digest": "eafb02ec0be9cefab7cef7c426c7d860d98e4947f4da04054154dc86d8f487c4"
+ },
+ {
"name": "flag_my",
"unicode": "1F1F2-1F1FE",
"digest": "9a690b357bc6b970781bd122c1e546ade3ccb73d930c2af1008b82027e36c7cf"
},
{
+ "name": "my",
+ "unicode": "1F1F2-1F1FE",
+ "digest": "9a690b357bc6b970781bd122c1e546ade3ccb73d930c2af1008b82027e36c7cf"
+ },
+ {
"name": "flag_mz",
"unicode": "1F1F2-1F1FF",
"digest": "36d0548ebfef9e0443ec1d0597ebfa6e95c25b997381f30c8c74008820743bb9"
},
{
+ "name": "mz",
+ "unicode": "1F1F2-1F1FF",
+ "digest": "36d0548ebfef9e0443ec1d0597ebfa6e95c25b997381f30c8c74008820743bb9"
+ },
+ {
"name": "flag_na",
"unicode": "1F1F3-1F1E6",
"digest": "4989dc9452b0bdfa101cfd3b7c83ef1195a7e45128b9ed00193fe712a6d02fca"
},
{
+ "name": "na",
+ "unicode": "1F1F3-1F1E6",
+ "digest": "4989dc9452b0bdfa101cfd3b7c83ef1195a7e45128b9ed00193fe712a6d02fca"
+ },
+ {
"name": "flag_nc",
"unicode": "1F1F3-1F1E8",
"digest": "7fc9d865eebf729d5496c4cd7576476ec599f65b379d4a6df66b4e399553c2eb"
},
{
+ "name": "nc",
+ "unicode": "1F1F3-1F1E8",
+ "digest": "7fc9d865eebf729d5496c4cd7576476ec599f65b379d4a6df66b4e399553c2eb"
+ },
+ {
"name": "flag_ne",
"unicode": "1F1F3-1F1EA",
"digest": "d3f10fb44ec44a04112bc66d05f0a44c6ec46dae73cfd3fe26cdc8b32ec06713"
},
{
+ "name": "ne",
+ "unicode": "1F1F3-1F1EA",
+ "digest": "d3f10fb44ec44a04112bc66d05f0a44c6ec46dae73cfd3fe26cdc8b32ec06713"
+ },
+ {
"name": "flag_nf",
"unicode": "1F1F3-1F1EB",
"digest": "d390e0d52215a025380af221ba9e955e5886edbb4c9f4b124f2fb60a8e019e42"
},
{
+ "name": "nf",
+ "unicode": "1F1F3-1F1EB",
+ "digest": "d390e0d52215a025380af221ba9e955e5886edbb4c9f4b124f2fb60a8e019e42"
+ },
+ {
"name": "flag_ng",
"unicode": "1F1F3-1F1EC",
"digest": "e69d1bb8f1db4a0c295c90dda23d8f97c2dea59f9a2da2ecb0e9a1dc4dbea101"
},
{
+ "name": "nigeria",
+ "unicode": "1F1F3-1F1EC",
+ "digest": "e69d1bb8f1db4a0c295c90dda23d8f97c2dea59f9a2da2ecb0e9a1dc4dbea101"
+ },
+ {
"name": "flag_ni",
"unicode": "1F1F3-1F1EE",
"digest": "dbaccc942637469b0ee75bd5f956958c3c5a89d8f69b69c96f02ab6594124894"
},
{
+ "name": "ni",
+ "unicode": "1F1F3-1F1EE",
+ "digest": "dbaccc942637469b0ee75bd5f956958c3c5a89d8f69b69c96f02ab6594124894"
+ },
+ {
"name": "flag_nl",
"unicode": "1F1F3-1F1F1",
"digest": "bda2eb0315763c3c19d37c664dab1ee4280f20888a0ca57677fd33cfa4240910"
},
{
+ "name": "nl",
+ "unicode": "1F1F3-1F1F1",
+ "digest": "bda2eb0315763c3c19d37c664dab1ee4280f20888a0ca57677fd33cfa4240910"
+ },
+ {
"name": "flag_no",
"unicode": "1F1F3-1F1F4",
"digest": "42b49dec756a220781ea271ca8fbcaba524dc3b38d5d8f999bfaa40ef9ebd302"
},
{
+ "name": "no",
+ "unicode": "1F1F3-1F1F4",
+ "digest": "42b49dec756a220781ea271ca8fbcaba524dc3b38d5d8f999bfaa40ef9ebd302"
+ },
+ {
"name": "flag_np",
"unicode": "1F1F3-1F1F5",
"digest": "b5259257db079235310d5d9537d2b5b61ae0326bc8920ba13084b009844e2957"
},
{
+ "name": "np",
+ "unicode": "1F1F3-1F1F5",
+ "digest": "b5259257db079235310d5d9537d2b5b61ae0326bc8920ba13084b009844e2957"
+ },
+ {
"name": "flag_nr",
"unicode": "1F1F3-1F1F7",
"digest": "1bd7d1fe2c3a5e98cfd4dff6e8d6dd6d3c74f0051ad615587d77d2291a9784cc"
},
{
+ "name": "nr",
+ "unicode": "1F1F3-1F1F7",
+ "digest": "1bd7d1fe2c3a5e98cfd4dff6e8d6dd6d3c74f0051ad615587d77d2291a9784cc"
+ },
+ {
"name": "flag_nu",
"unicode": "1F1F3-1F1FA",
"digest": "e2a7a398e07d2232147cc0917d72d18b519246d3d314e9f6f03dcf98d312d4ce"
},
{
+ "name": "nu",
+ "unicode": "1F1F3-1F1FA",
+ "digest": "e2a7a398e07d2232147cc0917d72d18b519246d3d314e9f6f03dcf98d312d4ce"
+ },
+ {
"name": "flag_nz",
"unicode": "1F1F3-1F1FF",
"digest": "ce8b1cb87dae3a3ec865575b57a0b4987a7f4bd3f170e7b210dd764fc2588cd4"
},
{
+ "name": "nz",
+ "unicode": "1F1F3-1F1FF",
+ "digest": "ce8b1cb87dae3a3ec865575b57a0b4987a7f4bd3f170e7b210dd764fc2588cd4"
+ },
+ {
"name": "flag_om",
"unicode": "1F1F4-1F1F2",
"digest": "29da72505a276a8a372a00c197388ebc5098c221cab26b3ff755bd62b10f740f"
},
{
+ "name": "om",
+ "unicode": "1F1F4-1F1F2",
+ "digest": "29da72505a276a8a372a00c197388ebc5098c221cab26b3ff755bd62b10f740f"
+ },
+ {
"name": "flag_pa",
"unicode": "1F1F5-1F1E6",
"digest": "180b673c9aceea43a8b55823a82d80600257e4982d0757d129860e3d8a14f458"
},
{
+ "name": "pa",
+ "unicode": "1F1F5-1F1E6",
+ "digest": "180b673c9aceea43a8b55823a82d80600257e4982d0757d129860e3d8a14f458"
+ },
+ {
"name": "flag_pe",
"unicode": "1F1F5-1F1EA",
"digest": "b61823ea2cd91e371e40832df5764558b81d44fac41030827a3f6d2564643c00"
},
{
+ "name": "pe",
+ "unicode": "1F1F5-1F1EA",
+ "digest": "b61823ea2cd91e371e40832df5764558b81d44fac41030827a3f6d2564643c00"
+ },
+ {
"name": "flag_pf",
"unicode": "1F1F5-1F1EB",
"digest": "e560421911f4af90c73a0dbdf8f42e69316003799304c9394fb127e3b83326fa"
},
{
+ "name": "pf",
+ "unicode": "1F1F5-1F1EB",
+ "digest": "e560421911f4af90c73a0dbdf8f42e69316003799304c9394fb127e3b83326fa"
+ },
+ {
"name": "flag_pg",
"unicode": "1F1F5-1F1EC",
"digest": "880e87db2ce0eac38db037683a5db46fd6ce30623cf56ae4a93a747103570044"
},
{
+ "name": "pg",
+ "unicode": "1F1F5-1F1EC",
+ "digest": "880e87db2ce0eac38db037683a5db46fd6ce30623cf56ae4a93a747103570044"
+ },
+ {
"name": "flag_ph",
"unicode": "1F1F5-1F1ED",
"digest": "49aae2f56bfd1385741dc76857aa1f1459778b2d39a1c955e469c5367585bfd5"
},
{
+ "name": "ph",
+ "unicode": "1F1F5-1F1ED",
+ "digest": "49aae2f56bfd1385741dc76857aa1f1459778b2d39a1c955e469c5367585bfd5"
+ },
+ {
"name": "flag_pk",
"unicode": "1F1F5-1F1F0",
"digest": "64379dbfc932df3a07935b5cfa11ca151f761d3728939e982604e12c663cd646"
},
{
+ "name": "pk",
+ "unicode": "1F1F5-1F1F0",
+ "digest": "64379dbfc932df3a07935b5cfa11ca151f761d3728939e982604e12c663cd646"
+ },
+ {
"name": "flag_pl",
"unicode": "1F1F5-1F1F1",
"digest": "3b688b074c2735d3dea0b7ab74b80eba243ce50cb05d68e585c9d701c1f14617"
},
{
+ "name": "pl",
+ "unicode": "1F1F5-1F1F1",
+ "digest": "3b688b074c2735d3dea0b7ab74b80eba243ce50cb05d68e585c9d701c1f14617"
+ },
+ {
"name": "flag_pm",
"unicode": "1F1F5-1F1F2",
"digest": "a13a69ee3131501dd8138173cfb669a35ee8039d84aa665e69dd7f0d0aa3e717"
},
{
+ "name": "pm",
+ "unicode": "1F1F5-1F1F2",
+ "digest": "a13a69ee3131501dd8138173cfb669a35ee8039d84aa665e69dd7f0d0aa3e717"
+ },
+ {
"name": "flag_pn",
"unicode": "1F1F5-1F1F3",
"digest": "d7ae3985cf66024e4a3001e79a8efbb3e75571f2b0abbd0fb87fc1efc795a2b3"
},
{
+ "name": "pn",
+ "unicode": "1F1F5-1F1F3",
+ "digest": "d7ae3985cf66024e4a3001e79a8efbb3e75571f2b0abbd0fb87fc1efc795a2b3"
+ },
+ {
"name": "flag_pr",
"unicode": "1F1F5-1F1F7",
"digest": "4910dc984bc908158506b770f28af56150cbb4509a4291947dfa2479b9e4b308"
},
{
+ "name": "pr",
+ "unicode": "1F1F5-1F1F7",
+ "digest": "4910dc984bc908158506b770f28af56150cbb4509a4291947dfa2479b9e4b308"
+ },
+ {
"name": "flag_ps",
"unicode": "1F1F5-1F1F8",
"digest": "b2bca7619fced25de94d7bd398537857460348a552e7d73d189aef3f428e6a13"
},
{
+ "name": "ps",
+ "unicode": "1F1F5-1F1F8",
+ "digest": "b2bca7619fced25de94d7bd398537857460348a552e7d73d189aef3f428e6a13"
+ },
+ {
"name": "flag_pt",
"unicode": "1F1F5-1F1F9",
"digest": "177282613b4b8b4d9551f1da6a1c3f66f1b96cf67c71c7d164213b26b3237395"
},
{
+ "name": "pt",
+ "unicode": "1F1F5-1F1F9",
+ "digest": "177282613b4b8b4d9551f1da6a1c3f66f1b96cf67c71c7d164213b26b3237395"
+ },
+ {
"name": "flag_pw",
"unicode": "1F1F5-1F1FC",
"digest": "2ff42a14bdc7df76b5f989dca381f94765032b26ae47d47b97844abde458cefe"
},
{
+ "name": "pw",
+ "unicode": "1F1F5-1F1FC",
+ "digest": "2ff42a14bdc7df76b5f989dca381f94765032b26ae47d47b97844abde458cefe"
+ },
+ {
"name": "flag_py",
"unicode": "1F1F5-1F1FE",
"digest": "80169b69a46c4c67d0090dc2c6bf05d1a14f133ac7ae56f811547e8e8f70d81b"
},
{
+ "name": "py",
+ "unicode": "1F1F5-1F1FE",
+ "digest": "80169b69a46c4c67d0090dc2c6bf05d1a14f133ac7ae56f811547e8e8f70d81b"
+ },
+ {
"name": "flag_qa",
"unicode": "1F1F6-1F1E6",
"digest": "589b44b975aa97426afb8db7f8b355491fca246b693903485824bf0f5a6953a2"
},
{
+ "name": "qa",
+ "unicode": "1F1F6-1F1E6",
+ "digest": "589b44b975aa97426afb8db7f8b355491fca246b693903485824bf0f5a6953a2"
+ },
+ {
"name": "flag_re",
"unicode": "1F1F7-1F1EA",
"digest": "77d242261742831a142c9ec74cd17d76b1e6d1af751ff3c6a356646744bc798a"
},
{
+ "name": "re",
+ "unicode": "1F1F7-1F1EA",
+ "digest": "77d242261742831a142c9ec74cd17d76b1e6d1af751ff3c6a356646744bc798a"
+ },
+ {
"name": "flag_ro",
"unicode": "1F1F7-1F1F4",
"digest": "d7d17026ea81f27456983722540f9a23343a3a1b22e7697c4fba118ce8b4719e"
},
{
+ "name": "ro",
+ "unicode": "1F1F7-1F1F4",
+ "digest": "d7d17026ea81f27456983722540f9a23343a3a1b22e7697c4fba118ce8b4719e"
+ },
+ {
"name": "flag_rs",
"unicode": "1F1F7-1F1F8",
"digest": "e466a18cc0368e623d3fe33a036c1e88db91ae24f7510e17caacc85c41f1bac8"
},
{
+ "name": "rs",
+ "unicode": "1F1F7-1F1F8",
+ "digest": "e466a18cc0368e623d3fe33a036c1e88db91ae24f7510e17caacc85c41f1bac8"
+ },
+ {
"name": "flag_ru",
"unicode": "1F1F7-1F1FA",
"digest": "86bf53a62dfc4c434d910f43df70f430fc67c0070fe3fc466c4fbfd6a5d8e646"
},
{
+ "name": "ru",
+ "unicode": "1F1F7-1F1FA",
+ "digest": "86bf53a62dfc4c434d910f43df70f430fc67c0070fe3fc466c4fbfd6a5d8e646"
+ },
+ {
"name": "flag_rw",
"unicode": "1F1F7-1F1FC",
"digest": "38ec5a01896c9747a8dbf865d5e8584770e587253b7af3d3b9c36cd993f67518"
},
{
+ "name": "rw",
+ "unicode": "1F1F7-1F1FC",
+ "digest": "38ec5a01896c9747a8dbf865d5e8584770e587253b7af3d3b9c36cd993f67518"
+ },
+ {
"name": "flag_sa",
"unicode": "1F1F8-1F1E6",
"digest": "a44d0b145f2a0b68eace24ecfd27519e9525ec764836728bc9c1fe96ccb811a0"
},
{
+ "name": "saudiarabia",
+ "unicode": "1F1F8-1F1E6",
+ "digest": "a44d0b145f2a0b68eace24ecfd27519e9525ec764836728bc9c1fe96ccb811a0"
+ },
+ {
+ "name": "saudi",
+ "unicode": "1F1F8-1F1E6",
+ "digest": "a44d0b145f2a0b68eace24ecfd27519e9525ec764836728bc9c1fe96ccb811a0"
+ },
+ {
"name": "flag_sb",
"unicode": "1F1F8-1F1E7",
"digest": "8ffa24c5cb92be4dbe43f6cd85b61b9608a3101bd78ebccff4fe99c209b3e241"
},
{
+ "name": "sb",
+ "unicode": "1F1F8-1F1E7",
+ "digest": "8ffa24c5cb92be4dbe43f6cd85b61b9608a3101bd78ebccff4fe99c209b3e241"
+ },
+ {
"name": "flag_sc",
"unicode": "1F1F8-1F1E8",
"digest": "227d090ac2cbf317e594567b6114b5063a13cfe33abf990d37b200debcfadabb"
},
{
+ "name": "sc",
+ "unicode": "1F1F8-1F1E8",
+ "digest": "227d090ac2cbf317e594567b6114b5063a13cfe33abf990d37b200debcfadabb"
+ },
+ {
"name": "flag_sd",
"unicode": "1F1F8-1F1E9",
"digest": "350f3332e8ea1138e54facc870dd0fea5f2ab7d3fd4baa02ed8627ae79642f6c"
},
{
+ "name": "sd",
+ "unicode": "1F1F8-1F1E9",
+ "digest": "350f3332e8ea1138e54facc870dd0fea5f2ab7d3fd4baa02ed8627ae79642f6c"
+ },
+ {
"name": "flag_se",
"unicode": "1F1F8-1F1EA",
"digest": "c1b09f36c263727de83b54376f05e083a17a61941af9a1640b826629256a280d"
},
{
+ "name": "se",
+ "unicode": "1F1F8-1F1EA",
+ "digest": "c1b09f36c263727de83b54376f05e083a17a61941af9a1640b826629256a280d"
+ },
+ {
"name": "flag_sg",
"unicode": "1F1F8-1F1EC",
"digest": "e6fc26920dfc07e4fd3c8d897de9c607e0bf48a3b64a13630c858d707a8e7660"
},
{
+ "name": "sg",
+ "unicode": "1F1F8-1F1EC",
+ "digest": "e6fc26920dfc07e4fd3c8d897de9c607e0bf48a3b64a13630c858d707a8e7660"
+ },
+ {
"name": "flag_sh",
"unicode": "1F1F8-1F1ED",
"digest": "f2c22ab0eb49e3104c35f1c0268b1e63c3a67f41b0cfa9861b189525988e53b6"
},
{
+ "name": "sh",
+ "unicode": "1F1F8-1F1ED",
+ "digest": "f2c22ab0eb49e3104c35f1c0268b1e63c3a67f41b0cfa9861b189525988e53b6"
+ },
+ {
"name": "flag_si",
"unicode": "1F1F8-1F1EE",
"digest": "1ef0b10e498f71591322f9d8ec122d39838f479370cf7ee922560986ef6c4f2e"
},
{
+ "name": "si",
+ "unicode": "1F1F8-1F1EE",
+ "digest": "1ef0b10e498f71591322f9d8ec122d39838f479370cf7ee922560986ef6c4f2e"
+ },
+ {
"name": "flag_sj",
"unicode": "1F1F8-1F1EF",
"digest": "ce913b007f84a9cba2add8d754aa791901624c60e4200de426dfa25271cb0f78"
},
{
+ "name": "sj",
+ "unicode": "1F1F8-1F1EF",
+ "digest": "ce913b007f84a9cba2add8d754aa791901624c60e4200de426dfa25271cb0f78"
+ },
+ {
"name": "flag_sk",
"unicode": "1F1F8-1F1F0",
"digest": "d8f8fc4024c82f906effe98facbef9d543fb3708b1134dc502c74dc4a442b30a"
},
{
+ "name": "sk",
+ "unicode": "1F1F8-1F1F0",
+ "digest": "d8f8fc4024c82f906effe98facbef9d543fb3708b1134dc502c74dc4a442b30a"
+ },
+ {
"name": "flag_sl",
"unicode": "1F1F8-1F1F1",
"digest": "dd7fd0452498d8d1c894cf0d5a662ddff9c5bcc02148bdc3dc7e6f25d0bb586e"
},
{
+ "name": "sl",
+ "unicode": "1F1F8-1F1F1",
+ "digest": "dd7fd0452498d8d1c894cf0d5a662ddff9c5bcc02148bdc3dc7e6f25d0bb586e"
+ },
+ {
"name": "flag_sm",
"unicode": "1F1F8-1F1F2",
"digest": "2b499606aee2b5cbf4037338753c80a4c8f75f4abcef2c8657bd9337e602bbd3"
},
{
+ "name": "sm",
+ "unicode": "1F1F8-1F1F2",
+ "digest": "2b499606aee2b5cbf4037338753c80a4c8f75f4abcef2c8657bd9337e602bbd3"
+ },
+ {
"name": "flag_sn",
"unicode": "1F1F8-1F1F3",
"digest": "03b46a9d8b129da13f60c23b820b04fba52050ca58a41b859ad57d5c3cc2515d"
},
{
+ "name": "sn",
+ "unicode": "1F1F8-1F1F3",
+ "digest": "03b46a9d8b129da13f60c23b820b04fba52050ca58a41b859ad57d5c3cc2515d"
+ },
+ {
"name": "flag_so",
"unicode": "1F1F8-1F1F4",
"digest": "ea416b6a05ddc5b16291ebe5101735360b08c834d55ac82c663ac1dd3e459048"
},
{
+ "name": "so",
+ "unicode": "1F1F8-1F1F4",
+ "digest": "ea416b6a05ddc5b16291ebe5101735360b08c834d55ac82c663ac1dd3e459048"
+ },
+ {
"name": "flag_sr",
"unicode": "1F1F8-1F1F7",
"digest": "012179fbcbcb7343e7b09d33e283fb63c7964a6eca35ccb9407d468e495a9874"
},
{
+ "name": "sr",
+ "unicode": "1F1F8-1F1F7",
+ "digest": "012179fbcbcb7343e7b09d33e283fb63c7964a6eca35ccb9407d468e495a9874"
+ },
+ {
"name": "flag_ss",
"unicode": "1F1F8-1F1F8",
"digest": "6723150482c640643c9dd7e33ea749f4a8b46aceacbd4f5e11aa33b3ee13aab7"
},
{
+ "name": "ss",
+ "unicode": "1F1F8-1F1F8",
+ "digest": "6723150482c640643c9dd7e33ea749f4a8b46aceacbd4f5e11aa33b3ee13aab7"
+ },
+ {
"name": "flag_st",
"unicode": "1F1F8-1F1F9",
"digest": "0947fcec2e3cb1b0e9943c3d00891e8ee226e8d0532e9b1fe807ddf2e8fbc49d"
},
{
+ "name": "st",
+ "unicode": "1F1F8-1F1F9",
+ "digest": "0947fcec2e3cb1b0e9943c3d00891e8ee226e8d0532e9b1fe807ddf2e8fbc49d"
+ },
+ {
"name": "flag_sv",
"unicode": "1F1F8-1F1FB",
"digest": "ce7e583db833c4b10e2f7a2d09b97bb522c02e96ea0b3f3a48a955f7d8f970d8"
},
{
+ "name": "sv",
+ "unicode": "1F1F8-1F1FB",
+ "digest": "ce7e583db833c4b10e2f7a2d09b97bb522c02e96ea0b3f3a48a955f7d8f970d8"
+ },
+ {
"name": "flag_sx",
"unicode": "1F1F8-1F1FD",
"digest": "c01fb238c7ba439f24a5ef821b6457f2a0fd0b99a1b2d02395bed87f0a4a88e5"
},
{
+ "name": "sx",
+ "unicode": "1F1F8-1F1FD",
+ "digest": "c01fb238c7ba439f24a5ef821b6457f2a0fd0b99a1b2d02395bed87f0a4a88e5"
+ },
+ {
"name": "flag_sy",
"unicode": "1F1F8-1F1FE",
"digest": "a77d87ef98c96140c59998d10d94837e2a056dd3ac5c7522e89e5c62eac69e69"
},
{
+ "name": "sy",
+ "unicode": "1F1F8-1F1FE",
+ "digest": "a77d87ef98c96140c59998d10d94837e2a056dd3ac5c7522e89e5c62eac69e69"
+ },
+ {
"name": "flag_sz",
"unicode": "1F1F8-1F1FF",
"digest": "2904ad01040a9107ad556ec4c2561781d96746005cca250babb1127b8ba21050"
},
{
+ "name": "sz",
+ "unicode": "1F1F8-1F1FF",
+ "digest": "2904ad01040a9107ad556ec4c2561781d96746005cca250babb1127b8ba21050"
+ },
+ {
"name": "flag_ta",
"unicode": "1F1F9-1F1E6",
"digest": "eda84db90e1a8854e8ff3c15b3b38ee65f7d6532b76970a6fbac304c30d8c959"
},
{
+ "name": "ta",
+ "unicode": "1F1F9-1F1E6",
+ "digest": "eda84db90e1a8854e8ff3c15b3b38ee65f7d6532b76970a6fbac304c30d8c959"
+ },
+ {
"name": "flag_tc",
"unicode": "1F1F9-1F1E8",
"digest": "4628fdf6dc598a2846beefe97f7d4c6812f4961394cec132924b44bbe79b3322"
},
{
+ "name": "tc",
+ "unicode": "1F1F9-1F1E8",
+ "digest": "4628fdf6dc598a2846beefe97f7d4c6812f4961394cec132924b44bbe79b3322"
+ },
+ {
"name": "flag_td",
"unicode": "1F1F9-1F1E9",
"digest": "125ff31e4285cb2a5493a52a2703ebe8e7138b918ec4dae3d0f8693632372df6"
},
{
+ "name": "td",
+ "unicode": "1F1F9-1F1E9",
+ "digest": "125ff31e4285cb2a5493a52a2703ebe8e7138b918ec4dae3d0f8693632372df6"
+ },
+ {
"name": "flag_tf",
"unicode": "1F1F9-1F1EB",
"digest": "489d591e11764ac341f2234020f7879db782b8f673fc9aae425fd713e4082334"
},
{
+ "name": "tf",
+ "unicode": "1F1F9-1F1EB",
+ "digest": "489d591e11764ac341f2234020f7879db782b8f673fc9aae425fd713e4082334"
+ },
+ {
"name": "flag_tg",
"unicode": "1F1F9-1F1EC",
"digest": "4ceedfcfcc22cd14d9add9d86d6748447995f19f7095fa4be883e21eb1aa86bc"
},
{
+ "name": "tg",
+ "unicode": "1F1F9-1F1EC",
+ "digest": "4ceedfcfcc22cd14d9add9d86d6748447995f19f7095fa4be883e21eb1aa86bc"
+ },
+ {
"name": "flag_th",
"unicode": "1F1F9-1F1ED",
"digest": "2798cc660af1c5dc4891c30aded3a53d7cfa0af128cc495df8141907b165902d"
},
{
+ "name": "th",
+ "unicode": "1F1F9-1F1ED",
+ "digest": "2798cc660af1c5dc4891c30aded3a53d7cfa0af128cc495df8141907b165902d"
+ },
+ {
"name": "flag_tj",
"unicode": "1F1F9-1F1EF",
"digest": "0483506fc5b5f2d4fc18ea3cd2f8a5da985d68fe4bf90bd3fd05e67e38f32398"
},
{
+ "name": "tj",
+ "unicode": "1F1F9-1F1EF",
+ "digest": "0483506fc5b5f2d4fc18ea3cd2f8a5da985d68fe4bf90bd3fd05e67e38f32398"
+ },
+ {
"name": "flag_tk",
"unicode": "1F1F9-1F1F0",
"digest": "d5d4a8c6ce3207731b7c154a9d8d8fa2af055a48f03b3cbbcfd3317d3b8a75f2"
},
{
+ "name": "tk",
+ "unicode": "1F1F9-1F1F0",
+ "digest": "d5d4a8c6ce3207731b7c154a9d8d8fa2af055a48f03b3cbbcfd3317d3b8a75f2"
+ },
+ {
"name": "flag_tl",
"unicode": "1F1F9-1F1F1",
"digest": "7a2ba8f91a6b627c60c88244223a9b9d0c12707f50b174f9c2eca07dd3440df7"
},
{
+ "name": "tl",
+ "unicode": "1F1F9-1F1F1",
+ "digest": "7a2ba8f91a6b627c60c88244223a9b9d0c12707f50b174f9c2eca07dd3440df7"
+ },
+ {
"name": "flag_tm",
"unicode": "1F1F9-1F1F2",
"digest": "adcf5f23adcf983ce626b44559482f8728251eab34b3ff5d8b125112f3a1010f"
},
{
+ "name": "turkmenistan",
+ "unicode": "1F1F9-1F1F2",
+ "digest": "adcf5f23adcf983ce626b44559482f8728251eab34b3ff5d8b125112f3a1010f"
+ },
+ {
"name": "flag_tn",
"unicode": "1F1F9-1F1F3",
"digest": "5ee690ee1f3c3c0cba9b36efdef902894ec59cefbc60c4baa341efd3d7bb9ba2"
},
{
+ "name": "tn",
+ "unicode": "1F1F9-1F1F3",
+ "digest": "5ee690ee1f3c3c0cba9b36efdef902894ec59cefbc60c4baa341efd3d7bb9ba2"
+ },
+ {
"name": "flag_to",
"unicode": "1F1F9-1F1F4",
"digest": "cde8672ca25b0e3a423865283fab9bc3ab10f472e04979b3b2f8032b71e96300"
},
{
+ "name": "to",
+ "unicode": "1F1F9-1F1F4",
+ "digest": "cde8672ca25b0e3a423865283fab9bc3ab10f472e04979b3b2f8032b71e96300"
+ },
+ {
"name": "flag_tr",
"unicode": "1F1F9-1F1F7",
"digest": "3d83c03ed084cfc81fa633310382acd7213e1eaa19d0ed97d142e7824032b55d"
},
{
+ "name": "tr",
+ "unicode": "1F1F9-1F1F7",
+ "digest": "3d83c03ed084cfc81fa633310382acd7213e1eaa19d0ed97d142e7824032b55d"
+ },
+ {
"name": "flag_tt",
"unicode": "1F1F9-1F1F9",
"digest": "d66d272ac27e2b398289d6b60128ccd3508aeb1f4a00a3920c5e6a21bfe357ed"
},
{
+ "name": "tt",
+ "unicode": "1F1F9-1F1F9",
+ "digest": "d66d272ac27e2b398289d6b60128ccd3508aeb1f4a00a3920c5e6a21bfe357ed"
+ },
+ {
"name": "flag_tv",
"unicode": "1F1F9-1F1FB",
"digest": "8716527383854cf1569f737d0f0f9ad77b46747255f24e02f5b2fbc850c2e35c"
},
{
+ "name": "tuvalu",
+ "unicode": "1F1F9-1F1FB",
+ "digest": "8716527383854cf1569f737d0f0f9ad77b46747255f24e02f5b2fbc850c2e35c"
+ },
+ {
"name": "flag_tw",
"unicode": "1F1F9-1F1FC",
"digest": "fb17b97e18e4423c5f60d60ec3ec60b917be579fc4dd9b5b23236786dcb35108"
},
{
+ "name": "tw",
+ "unicode": "1F1F9-1F1FC",
+ "digest": "fb17b97e18e4423c5f60d60ec3ec60b917be579fc4dd9b5b23236786dcb35108"
+ },
+ {
"name": "flag_tz",
"unicode": "1F1F9-1F1FF",
"digest": "a8a8cf57ae5227cb54620bf31d2d6e154d2067d6d049b8db64bc4e538222948b"
},
{
+ "name": "tz",
+ "unicode": "1F1F9-1F1FF",
+ "digest": "a8a8cf57ae5227cb54620bf31d2d6e154d2067d6d049b8db64bc4e538222948b"
+ },
+ {
"name": "flag_ua",
"unicode": "1F1FA-1F1E6",
"digest": "03aca4b3ffd60d944a5793eb7530f8d8ae527782f642f6606194e46ee314b12c"
},
{
+ "name": "ua",
+ "unicode": "1F1FA-1F1E6",
+ "digest": "03aca4b3ffd60d944a5793eb7530f8d8ae527782f642f6606194e46ee314b12c"
+ },
+ {
"name": "flag_ug",
"unicode": "1F1FA-1F1EC",
"digest": "70226a1585e88390b3b815b8b79a0ddb36d2961c6b465c4ff72aa444abfe982e"
},
{
+ "name": "ug",
+ "unicode": "1F1FA-1F1EC",
+ "digest": "70226a1585e88390b3b815b8b79a0ddb36d2961c6b465c4ff72aa444abfe982e"
+ },
+ {
"name": "flag_um",
"unicode": "1F1FA-1F1F2",
"digest": "aa83bf051149acf907140a860de5de1700710e4164ae5549ad1040b24d0a142b"
},
{
+ "name": "um",
+ "unicode": "1F1FA-1F1F2",
+ "digest": "aa83bf051149acf907140a860de5de1700710e4164ae5549ad1040b24d0a142b"
+ },
+ {
"name": "flag_us",
"unicode": "1F1FA-1F1F8",
"digest": "32ba2aa09a30514247e91d60762791b582f547a37d9151f98b700dff50f355ea"
},
{
+ "name": "us",
+ "unicode": "1F1FA-1F1F8",
+ "digest": "32ba2aa09a30514247e91d60762791b582f547a37d9151f98b700dff50f355ea"
+ },
+ {
"name": "flag_uy",
"unicode": "1F1FA-1F1FE",
"digest": "0e01b3f1df4bdf6d616dacc9c5825151b941bf074be750e8b24a07ea5d5bcacb"
},
{
+ "name": "uy",
+ "unicode": "1F1FA-1F1FE",
+ "digest": "0e01b3f1df4bdf6d616dacc9c5825151b941bf074be750e8b24a07ea5d5bcacb"
+ },
+ {
"name": "flag_uz",
"unicode": "1F1FA-1F1FF",
"digest": "903029ce83812a2134f24b65db35b183443a440ea5fecaa6ef7dcaaf65b2519c"
},
{
+ "name": "uz",
+ "unicode": "1F1FA-1F1FF",
+ "digest": "903029ce83812a2134f24b65db35b183443a440ea5fecaa6ef7dcaaf65b2519c"
+ },
+ {
"name": "flag_va",
"unicode": "1F1FB-1F1E6",
"digest": "fd3c1c5d0ac030e838f807288912c98a3e258f87901e252e46942a4dab9f8cb7"
},
{
+ "name": "va",
+ "unicode": "1F1FB-1F1E6",
+ "digest": "fd3c1c5d0ac030e838f807288912c98a3e258f87901e252e46942a4dab9f8cb7"
+ },
+ {
"name": "flag_vc",
"unicode": "1F1FB-1F1E8",
"digest": "7cd554ea8ca817b5366701160274587ab44167ae5a89c430bbaf237ea18b7421"
},
{
+ "name": "vc",
+ "unicode": "1F1FB-1F1E8",
+ "digest": "7cd554ea8ca817b5366701160274587ab44167ae5a89c430bbaf237ea18b7421"
+ },
+ {
"name": "flag_ve",
"unicode": "1F1FB-1F1EA",
"digest": "72930094fb088c1facabea07616035ec4771374358a90c3045219d087b350dd8"
},
{
+ "name": "ve",
+ "unicode": "1F1FB-1F1EA",
+ "digest": "72930094fb088c1facabea07616035ec4771374358a90c3045219d087b350dd8"
+ },
+ {
"name": "flag_vg",
"unicode": "1F1FB-1F1EC",
"digest": "78a59afd368b7a8312bfdb2f49927ff09e6b8f46aab0136c0453e3319e81df49"
},
{
+ "name": "vg",
+ "unicode": "1F1FB-1F1EC",
+ "digest": "78a59afd368b7a8312bfdb2f49927ff09e6b8f46aab0136c0453e3319e81df49"
+ },
+ {
"name": "flag_vi",
"unicode": "1F1FB-1F1EE",
"digest": "e070879f9605a9bae66bb84f2abf5a40c8b264baee65cd4f7a6720b826739f29"
},
{
+ "name": "vi",
+ "unicode": "1F1FB-1F1EE",
+ "digest": "e070879f9605a9bae66bb84f2abf5a40c8b264baee65cd4f7a6720b826739f29"
+ },
+ {
"name": "flag_vn",
"unicode": "1F1FB-1F1F3",
"digest": "100ddf06e0f239b170f4d6cb459450bf4945281ee818f7d3c061828b80562219"
},
{
+ "name": "vn",
+ "unicode": "1F1FB-1F1F3",
+ "digest": "100ddf06e0f239b170f4d6cb459450bf4945281ee818f7d3c061828b80562219"
+ },
+ {
"name": "flag_vu",
"unicode": "1F1FB-1F1FA",
"digest": "59fc9d16818295bba4f7f551598f85378cd07f2bd7e31a4eef2589aaa3847563"
},
{
+ "name": "vu",
+ "unicode": "1F1FB-1F1FA",
+ "digest": "59fc9d16818295bba4f7f551598f85378cd07f2bd7e31a4eef2589aaa3847563"
+ },
+ {
"name": "flag_wf",
"unicode": "1F1FC-1F1EB",
"digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
},
{
+ "name": "wf",
+ "unicode": "1F1FC-1F1EB",
+ "digest": "62627702e3e3768808c12f153a527ffcc492ad74d8cdc1858cfde971efd0c8ee"
+ },
+ {
"name": "flag_white",
"unicode": "1F3F3",
"digest": "96307e3a28e92d1e7147a06f154ffc291ee3cd1765cf8b7bfb06412294112559"
},
{
+ "name": "waving_white_flag",
+ "unicode": "1F3F3",
+ "digest": "96307e3a28e92d1e7147a06f154ffc291ee3cd1765cf8b7bfb06412294112559"
+ },
+ {
"name": "flag_ws",
"unicode": "1F1FC-1F1F8",
"digest": "0c95271d0f4b23f0d215ee0fba05cf08ecb70665d4c028e17463ecda2754b164"
},
{
+ "name": "ws",
+ "unicode": "1F1FC-1F1F8",
+ "digest": "0c95271d0f4b23f0d215ee0fba05cf08ecb70665d4c028e17463ecda2754b164"
+ },
+ {
"name": "flag_xk",
"unicode": "1F1FD-1F1F0",
"digest": "713aa7d228e96f4a06d58d1fb8c2a55296c3e56842f8177ca936f3e09f50da1e"
},
{
+ "name": "xk",
+ "unicode": "1F1FD-1F1F0",
+ "digest": "713aa7d228e96f4a06d58d1fb8c2a55296c3e56842f8177ca936f3e09f50da1e"
+ },
+ {
"name": "flag_ye",
"unicode": "1F1FE-1F1EA",
"digest": "3bb65bae9c913357bcae8b8b5878efc9e194ca308442ab69639c29716b49f078"
},
{
+ "name": "ye",
+ "unicode": "1F1FE-1F1EA",
+ "digest": "3bb65bae9c913357bcae8b8b5878efc9e194ca308442ab69639c29716b49f078"
+ },
+ {
"name": "flag_yt",
"unicode": "1F1FE-1F1F9",
"digest": "f86c86f4c194610a3af78971fcf221ad97b9499d08f6d64476e417a2f52a611e"
},
{
+ "name": "yt",
+ "unicode": "1F1FE-1F1F9",
+ "digest": "f86c86f4c194610a3af78971fcf221ad97b9499d08f6d64476e417a2f52a611e"
+ },
+ {
"name": "flag_za",
"unicode": "1F1FF-1F1E6",
"digest": "4dd4fa49a01fdcfc7c1c099a7869e0e9acba83a6a3debf6c8505ada4c796b872"
},
{
+ "name": "za",
+ "unicode": "1F1FF-1F1E6",
+ "digest": "4dd4fa49a01fdcfc7c1c099a7869e0e9acba83a6a3debf6c8505ada4c796b872"
+ },
+ {
"name": "flag_zm",
"unicode": "1F1FF-1F1F2",
"digest": "ab6790d89875447de3d1c7f4713b102761bc3e9afdd714b818689e175ca03011"
},
{
+ "name": "zm",
+ "unicode": "1F1FF-1F1F2",
+ "digest": "ab6790d89875447de3d1c7f4713b102761bc3e9afdd714b818689e175ca03011"
+ },
+ {
"name": "flag_zw",
"unicode": "1F1FF-1F1FC",
"digest": "9d39b934fe922174b2250f2cd1b174a548d2904091d3298f35b7cc59fbceb181"
},
{
+ "name": "zw",
+ "unicode": "1F1FF-1F1FC",
+ "digest": "9d39b934fe922174b2250f2cd1b174a548d2904091d3298f35b7cc59fbceb181"
+ },
+ {
"name": "flags",
"unicode": "1F38F",
"digest": "c3f4a66786e524a5562919afcba9486113091ed205f1342e91d2f6439845ad61"
@@ -3670,11 +5305,21 @@
"digest": "be59efba4bc0759af5a726c06619090ef5071bf2541611d71691dedecee6c697"
},
{
+ "name": "clamshell_mobile_phone",
+ "unicode": "1F581",
+ "digest": "be59efba4bc0759af5a726c06619090ef5071bf2541611d71691dedecee6c697"
+ },
+ {
"name": "floppy_black",
"unicode": "1F5AA",
"digest": "9022f51bb09c5130c6d46bb2accb159bed6f54d6fbffda6ecad62965ebc958ea"
},
{
+ "name": "black_hard_shell_floppy_disk",
+ "unicode": "1F5AA",
+ "digest": "9022f51bb09c5130c6d46bb2accb159bed6f54d6fbffda6ecad62965ebc958ea"
+ },
+ {
"name": "floppy_disk",
"unicode": "1F4BE",
"digest": "e987961ca516032a90942ef6c398836f2da68a5981714bd172acfe7b0e369d0a"
@@ -3685,6 +5330,11 @@
"digest": "ec79c400117c4506ef8cf3eebef6c42dd37e60b3079d3e98b6ccd06e517e2af0"
},
{
+ "name": "white_hard_shell_floppy_disk",
+ "unicode": "1F5AB",
+ "digest": "ec79c400117c4506ef8cf3eebef6c42dd37e60b3079d3e98b6ccd06e517e2af0"
+ },
+ {
"name": "flower_playing_cards",
"unicode": "1F3B4",
"digest": "451f361050b96ba9ed8dc5b64c8a90c1316fd9b83fb818152881a54e100eea6c"
@@ -3715,6 +5365,11 @@
"digest": "74f3b484771c3d6ef61cf003de25c1a59b875afa46c057b5b1d92d9f99460685"
},
{
+ "name": "open_folder",
+ "unicode": "1F5C1",
+ "digest": "74f3b484771c3d6ef61cf003de25c1a59b875afa46c057b5b1d92d9f99460685"
+ },
+ {
"name": "football",
"unicode": "1F3C8",
"digest": "834fe5f431d6aa8ef1186aa79e71f813393535d273483b6af4cc4bdb8380e5b4"
@@ -3735,6 +5390,11 @@
"digest": "b4081b9edea6cdab5112fdd17535051ba17710953013f5020c7c40f84a1e3247"
},
{
+ "name": "fork_and_knife_with_plate",
+ "unicode": "1F37D",
+ "digest": "b4081b9edea6cdab5112fdd17535051ba17710953013f5020c7c40f84a1e3247"
+ },
+ {
"name": "fountain",
"unicode": "26F2",
"digest": "0acdca5e8f6d745a8d582d96012ec8fc55b9f5447e657ebfd998a4e332d99322"
@@ -3755,16 +5415,31 @@
"digest": "6ff21063063989c6ae7dd69f4d6a781c676f9dba380d8e6f1dbac5d53b24f349"
},
{
+ "name": "frame_with_picture",
+ "unicode": "1F5BC",
+ "digest": "6ff21063063989c6ae7dd69f4d6a781c676f9dba380d8e6f1dbac5d53b24f349"
+ },
+ {
"name": "frame_tiles",
"unicode": "1F5BD",
"digest": "34a5bb044b4b3ad94b116ad106f7b6747fb8612dc0e9f8ccd4313c2920508df0"
},
{
+ "name": "frame_with_tiles",
+ "unicode": "1F5BD",
+ "digest": "34a5bb044b4b3ad94b116ad106f7b6747fb8612dc0e9f8ccd4313c2920508df0"
+ },
+ {
"name": "frame_x",
"unicode": "1F5BE",
"digest": "2e427688fd70361c8c59787d0722ad68abe1c3f968258ee99c0c77ce4b8a8e15"
},
{
+ "name": "frame_with_an_x",
+ "unicode": "1F5BE",
+ "digest": "2e427688fd70361c8c59787d0722ad68abe1c3f968258ee99c0c77ce4b8a8e15"
+ },
+ {
"name": "free",
"unicode": "1F193",
"digest": "c1d9172a656717f78d941303c5da8790c6cd9827838d8f7dc3719afb53bcab80"
@@ -3790,11 +5465,21 @@
"digest": "fb39f5c2aea98054adb02a3a0ac34a2e38d83f32cd590e9d2449e06a9702f2f5"
},
{
+ "name": "anguished",
+ "unicode": "1F626",
+ "digest": "fb39f5c2aea98054adb02a3a0ac34a2e38d83f32cd590e9d2449e06a9702f2f5"
+ },
+ {
"name": "frowning2",
"unicode": "2639",
"digest": "7bb6c682a6c9f98bf3a5ae986e317fd26d1af497c857500deec2f06b6a3af5da"
},
{
+ "name": "white_frowning_face",
+ "unicode": "2639",
+ "digest": "7bb6c682a6c9f98bf3a5ae986e317fd26d1af497c857500deec2f06b6a3af5da"
+ },
+ {
"name": "fuelpump",
"unicode": "26FD",
"digest": "9cbb2646c93b255bd3de87dc01aa1193ab96e39a3013975d250472ab8aae61d6"
@@ -4030,6 +5715,11 @@
"digest": "2e4fe33406ca03fbb0df1596d63e903d8ee6bd78ecc3ec38a67dd2cecbc584e2"
},
{
+ "name": "hammer_and_pick",
+ "unicode": "2692",
+ "digest": "2e4fe33406ca03fbb0df1596d63e903d8ee6bd78ecc3ec38a67dd2cecbc584e2"
+ },
+ {
"name": "hamster",
"unicode": "1F439",
"digest": "f47da088ff5792532a382b6e3a47d2dd7c5e6fc19abd5ff6c5ba3ce420b4192e"
@@ -4040,41 +5730,81 @@
"digest": "a43e52f7cdec5e9d51497888b0988d7bbd42846ad7e492b196293fbce576d197"
},
{
+ "name": "raised_hand_with_fingers_splayed",
+ "unicode": "1F590",
+ "digest": "a43e52f7cdec5e9d51497888b0988d7bbd42846ad7e492b196293fbce576d197"
+ },
+ {
"name": "hand_splayed_reverse",
"unicode": "1F591",
"digest": "ff0af0fe9def7388adca6836e5958492282b1afae99f1b6e1e65d11ba68b96db"
},
{
+ "name": "reversed_raised_hand_with_fingers_splayed",
+ "unicode": "1F591",
+ "digest": "ff0af0fe9def7388adca6836e5958492282b1afae99f1b6e1e65d11ba68b96db"
+ },
+ {
"name": "hand_splayed_tone1",
"unicode": "1F590-1F3FB",
"digest": "73cceec7117280d330f8a149979190f0f355dd8d0a92821be89fb70344bb8dfe"
},
{
+ "name": "raised_hand_with_fingers_splayed_tone1",
+ "unicode": "1F590-1F3FB",
+ "digest": "73cceec7117280d330f8a149979190f0f355dd8d0a92821be89fb70344bb8dfe"
+ },
+ {
"name": "hand_splayed_tone2",
"unicode": "1F590-1F3FC",
"digest": "b06fac698128f4c3a7b8ea56e8bc4de088bb5461aa0f9c84553f16b43d347145"
},
{
+ "name": "raised_hand_with_fingers_splayed_tone2",
+ "unicode": "1F590-1F3FC",
+ "digest": "b06fac698128f4c3a7b8ea56e8bc4de088bb5461aa0f9c84553f16b43d347145"
+ },
+ {
"name": "hand_splayed_tone3",
"unicode": "1F590-1F3FD",
"digest": "a94ee9a2f8cdec6d2f7dd6887d1c7b8e064fcad63030c2c7c001742d72b5603e"
},
{
+ "name": "raised_hand_with_fingers_splayed_tone3",
+ "unicode": "1F590-1F3FD",
+ "digest": "a94ee9a2f8cdec6d2f7dd6887d1c7b8e064fcad63030c2c7c001742d72b5603e"
+ },
+ {
"name": "hand_splayed_tone4",
"unicode": "1F590-1F3FE",
"digest": "501792b4126c6f32e755accee0fc8b4d1915e1d36c4ceaa40f3bd0066efe76c3"
},
{
+ "name": "raised_hand_with_fingers_splayed_tone4",
+ "unicode": "1F590-1F3FE",
+ "digest": "501792b4126c6f32e755accee0fc8b4d1915e1d36c4ceaa40f3bd0066efe76c3"
+ },
+ {
"name": "hand_splayed_tone5",
"unicode": "1F590-1F3FF",
"digest": "22ed533d587cf44f286e2d6ad77be20b4b5f133c422af4ca51e9af86a75002d8"
},
{
+ "name": "raised_hand_with_fingers_splayed_tone5",
+ "unicode": "1F590-1F3FF",
+ "digest": "22ed533d587cf44f286e2d6ad77be20b4b5f133c422af4ca51e9af86a75002d8"
+ },
+ {
"name": "hand_victory",
"unicode": "1F594",
"digest": "2d512ced4e8a438f2a346aed67310d3080f9828c748ade1be95943c32ba1c735"
},
{
+ "name": "reversed_victory_hand",
+ "unicode": "1F594",
+ "digest": "2d512ced4e8a438f2a346aed67310d3080f9828c748ade1be95943c32ba1c735"
+ },
+ {
"name": "handbag",
"unicode": "1F45C",
"digest": "f1e2822c67f659b52c76821dd9db001332215a8566fc1846c89b6019c9758038"
@@ -4105,6 +5835,11 @@
"digest": "d690b740ff4f58e89dfc764c6411a4e84cfedffd7694eb5efa839a642dbabd08"
},
{
+ "name": "face_with_head_bandage",
+ "unicode": "1F915",
+ "digest": "d690b740ff4f58e89dfc764c6411a4e84cfedffd7694eb5efa839a642dbabd08"
+ },
+ {
"name": "headphones",
"unicode": "1F3A7",
"digest": "219da138032c01c97a94f02b211049418191a3beb3d159804b9033f5916fd3c8"
@@ -4130,6 +5865,11 @@
"digest": "9751c89dcf10805f2011949ff3ddcb6bcb13de8c32ae5de9e03955e8a4235df2"
},
{
+ "name": "heavy_heart_exclamation_mark_ornament",
+ "unicode": "2763",
+ "digest": "9751c89dcf10805f2011949ff3ddcb6bcb13de8c32ae5de9e03955e8a4235df2"
+ },
+ {
"name": "heart_eyes",
"unicode": "1F60D",
"digest": "335ea73efca4824e623a5a51ccdb494c8b1f5f10b4139b39b250a2a771876b0d"
@@ -4145,6 +5885,11 @@
"digest": "2178829e2c85accda55d2f685544587f6de5c8398a127ae1e08ff1c4ab282204"
},
{
+ "name": "heart_with_tip_on_the_left",
+ "unicode": "1F394",
+ "digest": "2178829e2c85accda55d2f685544587f6de5c8398a127ae1e08ff1c4ab282204"
+ },
+ {
"name": "heartbeat",
"unicode": "1F493",
"digest": "cd6921ce55c155873220a09416d695c4bcca1556007066d6d185e93d6561e825"
@@ -4200,6 +5945,11 @@
"digest": "affbe9dd87b87ff9235b4858c59c2a73e9ed30dd5221e5b666b8d7747378a9c4"
},
{
+ "name": "helmet_with_white_cross",
+ "unicode": "26D1",
+ "digest": "affbe9dd87b87ff9235b4858c59c2a73e9ed30dd5221e5b666b8d7747378a9c4"
+ },
+ {
"name": "herb",
"unicode": "1F33F",
"digest": "3c452106b1966f643751bf161fa7d1762a33e6fff381b2109bb53b55c4fdd129"
@@ -4235,6 +5985,11 @@
"digest": "9980d6dd6cbd23b820747ecac4cb10974dd24b0c94b4acfe21fa87793ad065c9"
},
{
+ "name": "house_buildings",
+ "unicode": "1F3D8",
+ "digest": "9980d6dd6cbd23b820747ecac4cb10974dd24b0c94b4acfe21fa87793ad065c9"
+ },
+ {
"name": "honey_pot",
"unicode": "1F36F",
"digest": "94cb1624491076b5cb145e7a309f91a7be3d4c0bed712af6a51d641eb73edee7"
@@ -4290,6 +6045,11 @@
"digest": "58b829e26b5c4642942898d9c7873cb08e048fd7deaacba8292899d5d895cb2b"
},
{
+ "name": "hot_dog",
+ "unicode": "1F32D",
+ "digest": "58b829e26b5c4642942898d9c7873cb08e048fd7deaacba8292899d5d895cb2b"
+ },
+ {
"name": "hotel",
"unicode": "1F3E8",
"digest": "428120a35b38a217901e10d704751eb8fdbc9f805e6eccd8aab070f4311b2085"
@@ -4320,6 +6080,11 @@
"digest": "e404631e3a296bdeae3de7510da8934c32327bc0fa0f7ae4e676b61932165668"
},
{
+ "name": "derelict_house_building",
+ "unicode": "1F3DA",
+ "digest": "e404631e3a296bdeae3de7510da8934c32327bc0fa0f7ae4e676b61932165668"
+ },
+ {
"name": "house_with_garden",
"unicode": "1F3E1",
"digest": "22d0d911da96b7ae3bf6692d3cf3590afbca959fc99c13e7a088f7194f43a35d"
@@ -4330,6 +6095,11 @@
"digest": "68ed6c4e0eae9071cf67770a39e07a2290b4f7763170f765b3cd3ac67ae43240"
},
{
+ "name": "hugging_face",
+ "unicode": "1F917",
+ "digest": "68ed6c4e0eae9071cf67770a39e07a2290b4f7763170f765b3cd3ac67ae43240"
+ },
+ {
"name": "hushed",
"unicode": "1F62F",
"digest": "69faa8e0b170ee8cf41977ca4a5154406360ed9699d5c62ecdaa01f50e8e4276"
@@ -4380,6 +6150,11 @@
"digest": "59c35e77d5ee663c5d56f7d8af845ce8aeb9935e526ae4a06e02ae70e71212ca"
},
{
+ "name": "circled_information_source",
+ "unicode": "1F6C8",
+ "digest": "59c35e77d5ee663c5d56f7d8af845ce8aeb9935e526ae4a06e02ae70e71212ca"
+ },
+ {
"name": "information_desk_person",
"unicode": "1F481",
"digest": "acae6d272e348aee87dd60360f16ac58cea7cb4e1ea962cc1655005c7f4aed27"
@@ -4435,6 +6210,11 @@
"digest": "17f02b309b62ed9542b1d8943168302846040e420f413e56d799bb5fba7064fa"
},
{
+ "name": "desert_island",
+ "unicode": "1F3DD",
+ "digest": "17f02b309b62ed9542b1d8943168302846040e420f413e56d799bb5fba7064fa"
+ },
+ {
"name": "izakaya_lantern",
"unicode": "1F3EE",
"digest": "ddb20f475aa119c3a64a55dff40f7a9dbc3a14f7ffc6cfbac89210c652f10d02"
@@ -4475,6 +6255,11 @@
"digest": "3708e5e034b1c64d1268d66527e13c369aa0f8903bce9172bef773b2d1940948"
},
{
+ "name": "up_pointing_military_airplane",
+ "unicode": "1F6E6",
+ "digest": "3708e5e034b1c64d1268d66527e13c369aa0f8903bce9172bef773b2d1940948"
+ },
+ {
"name": "joy",
"unicode": "1F602",
"digest": "f90cfbcb14f906f8d786b61f022c978f381fc99ca422805f605631314e101805"
@@ -4505,21 +6290,41 @@
"digest": "87a7d42531d7a11dcb11b0d6d1be611ee8cec35b5d22226a8ac6083fedef4f5d"
},
{
+ "name": "old_key",
+ "unicode": "1F5DD",
+ "digest": "87a7d42531d7a11dcb11b0d6d1be611ee8cec35b5d22226a8ac6083fedef4f5d"
+ },
+ {
"name": "keyboard",
"unicode": "1F5AE",
"digest": "3b254cbf19946df3af05e501d11653d89fcda91684b7248d86186f842b83bf16"
},
{
+ "name": "wired_keyboard",
+ "unicode": "1F5AE",
+ "digest": "3b254cbf19946df3af05e501d11653d89fcda91684b7248d86186f842b83bf16"
+ },
+ {
"name": "keyboard_mouse",
"unicode": "1F5A6",
"digest": "95b523e55d8afeaeb06442bbe20e47f49643bb0c32d89a8cdbbccdead20532b3"
},
{
+ "name": "keyboard_and_mouse",
+ "unicode": "1F5A6",
+ "digest": "95b523e55d8afeaeb06442bbe20e47f49643bb0c32d89a8cdbbccdead20532b3"
+ },
+ {
"name": "keyboard_with_jacks",
"unicode": "1F398",
"digest": "e29a0d0b8018d13458469edca13c60a882a2817957c1aa11b050684c995a47ee"
},
{
+ "name": "musical_keyboard_with_jacks",
+ "unicode": "1F398",
+ "digest": "e29a0d0b8018d13458469edca13c60a882a2817957c1aa11b050684c995a47ee"
+ },
+ {
"name": "keycap_ten",
"unicode": "1F51F",
"digest": "7593aa7ffe7192a2e35c6ccec76522f6243777783c9152c7c03419835ea58c03"
@@ -4540,11 +6345,21 @@
"digest": "381364ad988ec07cc3708fd60f71838092224009088fff587069b4e8ab01ee63"
},
{
+ "name": "couplekiss_mm",
+ "unicode": "1F468-2764-1F48B-1F468",
+ "digest": "381364ad988ec07cc3708fd60f71838092224009088fff587069b4e8ab01ee63"
+ },
+ {
"name": "kiss_ww",
"unicode": "1F469-2764-1F48B-1F469",
"digest": "7705ca707b73f44c856ea324bdfe30ed05244c8d192d1111f6e1d62ab3f2f8a5"
},
{
+ "name": "couplekiss_ww",
+ "unicode": "1F469-2764-1F48B-1F469",
+ "digest": "7705ca707b73f44c856ea324bdfe30ed05244c8d192d1111f6e1d62ab3f2f8a5"
+ },
+ {
"name": "kissing",
"unicode": "1F617",
"digest": "3142617e8b9488689bd9efc67c0e4cc71a1870df8ffc308f949eedc5c3684051"
@@ -4620,6 +6435,11 @@
"digest": "f22d3be77f1daf058d04c3cbc1fd7f76b4dc069d2d300b45e63e768b08d269c5"
},
{
+ "name": "satisfied",
+ "unicode": "1F606",
+ "digest": "f22d3be77f1daf058d04c3cbc1fd7f76b4dc069d2d300b45e63e768b08d269c5"
+ },
+ {
"name": "leaves",
"unicode": "1F343",
"digest": "f65e2db125564eb04fc427a49fff175d6e2dae847bd12314d5e6a131610d5ccd"
@@ -4640,6 +6460,11 @@
"digest": "8052e44951afee04c87296128744b5019ec783c9ed1a231f659af6c8ddaa50f3"
},
{
+ "name": "left_hand_telephone_receiver",
+ "unicode": "1F57B",
+ "digest": "8052e44951afee04c87296128744b5019ec783c9ed1a231f659af6c8ddaa50f3"
+ },
+ {
"name": "left_right_arrow",
"unicode": "2194",
"digest": "28a6945972451b1f4dadec5c55310b8868ffd9f3b0a07803287bc4e07a56e7d4"
@@ -4675,6 +6500,11 @@
"digest": "3e4e9a5ac6a8dbd7909c58a9d915f16f1a0fc59cc019714ae5935f18e4704044"
},
{
+ "name": "man_in_business_suit_levitating",
+ "unicode": "1F574",
+ "digest": "3e4e9a5ac6a8dbd7909c58a9d915f16f1a0fc59cc019714ae5935f18e4704044"
+ },
+ {
"name": "libra",
"unicode": "264E",
"digest": "ec8e2e7a735abc9f2bddb115fc0e09f4bdc7a164679e2b57d127f58eee1155c2"
@@ -4685,36 +6515,71 @@
"digest": "f64db037fd21e5918e5de35d6a561ef4b44668e307ed351338de00fcf3e771e3"
},
{
+ "name": "weight_lifter",
+ "unicode": "1F3CB",
+ "digest": "f64db037fd21e5918e5de35d6a561ef4b44668e307ed351338de00fcf3e771e3"
+ },
+ {
"name": "lifter_tone1",
"unicode": "1F3CB-1F3FB",
"digest": "f9e0d161b12c4908ac3409b11c1a77ee38f33ba018f12416545876214bfb7c01"
},
{
+ "name": "weight_lifter_tone1",
+ "unicode": "1F3CB-1F3FB",
+ "digest": "f9e0d161b12c4908ac3409b11c1a77ee38f33ba018f12416545876214bfb7c01"
+ },
+ {
"name": "lifter_tone2",
"unicode": "1F3CB-1F3FC",
"digest": "631eb6ed5bd147dc6f1f8b94149abe44d62a0f78e7809e37a4bfe127c40ed98f"
},
{
+ "name": "weight_lifter_tone2",
+ "unicode": "1F3CB-1F3FC",
+ "digest": "631eb6ed5bd147dc6f1f8b94149abe44d62a0f78e7809e37a4bfe127c40ed98f"
+ },
+ {
"name": "lifter_tone3",
"unicode": "1F3CB-1F3FD",
"digest": "406b5707a47d9066f016acf0b64fa695e3505acc2453758a0428de21efd7eb6d"
},
{
+ "name": "weight_lifter_tone3",
+ "unicode": "1F3CB-1F3FD",
+ "digest": "406b5707a47d9066f016acf0b64fa695e3505acc2453758a0428de21efd7eb6d"
+ },
+ {
"name": "lifter_tone4",
"unicode": "1F3CB-1F3FE",
"digest": "d917164ed8c4bb1ffcc887ca256ec329e7fa1b9516eaf8c159f8b43fdb071ed6"
},
{
+ "name": "weight_lifter_tone4",
+ "unicode": "1F3CB-1F3FE",
+ "digest": "d917164ed8c4bb1ffcc887ca256ec329e7fa1b9516eaf8c159f8b43fdb071ed6"
+ },
+ {
"name": "lifter_tone5",
"unicode": "1F3CB-1F3FF",
"digest": "f79ea93e8a40b3c895b693bf49eb4ce6e7b3f4413595e5881ea44839fd7fe8e5"
},
{
+ "name": "weight_lifter_tone5",
+ "unicode": "1F3CB-1F3FF",
+ "digest": "f79ea93e8a40b3c895b693bf49eb4ce6e7b3f4413595e5881ea44839fd7fe8e5"
+ },
+ {
"name": "light_check_mark",
"unicode": "1F5F8",
"digest": "7842b0df8c2b6703bed0cce5d2790d394eec7120b2a245a76f375528f2729a7b"
},
{
+ "name": "light_mark",
+ "unicode": "1F5F8",
+ "digest": "7842b0df8c2b6703bed0cce5d2790d394eec7120b2a245a76f375528f2729a7b"
+ },
+ {
"name": "light_rail",
"unicode": "1F688",
"digest": "7c2be55456f1332e849ff6699a26dda2e1641c280f45c9ec88dedf6d9b7b7fe2"
@@ -4730,6 +6595,11 @@
"digest": "935b1076815f51fafcd860a395d0a03c536acfcea61ffcf542a377da046fa7d9"
},
{
+ "name": "lion",
+ "unicode": "1F981",
+ "digest": "935b1076815f51fafcd860a395d0a03c536acfcea61ffcf542a377da046fa7d9"
+ },
+ {
"name": "lips",
"unicode": "1F444",
"digest": "e3bc20f9e210fa1711271234fe61bf1c9ddf36dd6ffc5b832c6c3a769a1e59a8"
@@ -4930,6 +6800,11 @@
"digest": "f56116d09996d6d08fb5cdfb46622b545253f2649008170fc2011a9713fa875b"
},
{
+ "name": "world_map",
+ "unicode": "1F5FA",
+ "digest": "f56116d09996d6d08fb5cdfb46622b545253f2649008170fc2011a9713fa875b"
+ },
+ {
"name": "maple_leaf",
"unicode": "1F341",
"digest": "40c5ee93396301911391cf6e70454b6fa8020fe5c85d3364136bcedb5d052cdb"
@@ -4980,6 +6855,11 @@
"digest": "270d438b6e2155e944dc734ea3e4d02409e51f59db2db636398fbf96e5edb0e6"
},
{
+ "name": "sports_medal",
+ "unicode": "1F3C5",
+ "digest": "270d438b6e2155e944dc734ea3e4d02409e51f59db2db636398fbf96e5edb0e6"
+ },
+ {
"name": "mega",
"unicode": "1F4E3",
"digest": "540ab4fd5bab041a681749b85e6de598ebcbfc4fbf5c3cdbd9ca1e8256191733"
@@ -5005,31 +6885,61 @@
"digest": "45e5fac0b9b019cf217dcfd1380cafb0d03063454612178278dac1ca5f8476a6"
},
{
+ "name": "sign_of_the_horns",
+ "unicode": "1F918",
+ "digest": "45e5fac0b9b019cf217dcfd1380cafb0d03063454612178278dac1ca5f8476a6"
+ },
+ {
"name": "metal_tone1",
"unicode": "1F918-1F3FB",
"digest": "9b3596fe7c063df838f0a43fb680ce10fb88e2b73c5c3324abfa357a224c17aa"
},
{
+ "name": "sign_of_the_horns_tone1",
+ "unicode": "1F918-1F3FB",
+ "digest": "9b3596fe7c063df838f0a43fb680ce10fb88e2b73c5c3324abfa357a224c17aa"
+ },
+ {
"name": "metal_tone2",
"unicode": "1F918-1F3FC",
"digest": "e15a4898a0efca4354ac48d6b01ff0618ce8b110b1246a4f5d78e19b54658be6"
},
{
+ "name": "sign_of_the_horns_tone2",
+ "unicode": "1F918-1F3FC",
+ "digest": "e15a4898a0efca4354ac48d6b01ff0618ce8b110b1246a4f5d78e19b54658be6"
+ },
+ {
"name": "metal_tone3",
"unicode": "1F918-1F3FD",
"digest": "c159e8179cb1907c246b432d87c5253b914fd7cebb6ac05292c4e38eff4815b0"
},
{
+ "name": "sign_of_the_horns_tone3",
+ "unicode": "1F918-1F3FD",
+ "digest": "c159e8179cb1907c246b432d87c5253b914fd7cebb6ac05292c4e38eff4815b0"
+ },
+ {
"name": "metal_tone4",
"unicode": "1F918-1F3FE",
"digest": "a8a43a88028c97074321e3da56df1045db41ede58bf286c21d7ae90f222f2011"
},
{
+ "name": "sign_of_the_horns_tone4",
+ "unicode": "1F918-1F3FE",
+ "digest": "a8a43a88028c97074321e3da56df1045db41ede58bf286c21d7ae90f222f2011"
+ },
+ {
"name": "metal_tone5",
"unicode": "1F918-1F3FF",
"digest": "e6611e826e867e2c73a8cadb138e4aa6365e3583dd229ff24b3e8f161904bf56"
},
{
+ "name": "sign_of_the_horns_tone5",
+ "unicode": "1F918-1F3FF",
+ "digest": "e6611e826e867e2c73a8cadb138e4aa6365e3583dd229ff24b3e8f161904bf56"
+ },
+ {
"name": "metro",
"unicode": "1F687",
"digest": "532378cf385f9a7fafe2f5c8203e675be6d38798871f4c8e2c50498a1529f956"
@@ -5045,6 +6955,11 @@
"digest": "f9df32cd207808f67a895d3460a215d1ecc42e377907bcd64731c02b697d4f32"
},
{
+ "name": "studio_microphone",
+ "unicode": "1F399",
+ "digest": "f9df32cd207808f67a895d3460a215d1ecc42e377907bcd64731c02b697d4f32"
+ },
+ {
"name": "microscope",
"unicode": "1F52C",
"digest": "79918f5fe0a39f31f270a481f4c6e00ea49fc09d64b1ae78770971293c2b1ed8"
@@ -5055,31 +6970,61 @@
"digest": "c6320b236a4a9593aeade511b52dd3114207e947458cb3b818c78737a505fdf6"
},
{
+ "name": "reversed_hand_with_middle_finger_extended",
+ "unicode": "1F595",
+ "digest": "c6320b236a4a9593aeade511b52dd3114207e947458cb3b818c78737a505fdf6"
+ },
+ {
"name": "middle_finger_tone1",
"unicode": "1F595-1F3FB",
"digest": "93c7aa994856185519d576cb779bdcff3a33f7077eef98e70968125f92f02448"
},
{
+ "name": "reversed_hand_with_middle_finger_extended_tone1",
+ "unicode": "1F595-1F3FB",
+ "digest": "93c7aa994856185519d576cb779bdcff3a33f7077eef98e70968125f92f02448"
+ },
+ {
"name": "middle_finger_tone2",
"unicode": "1F595-1F3FC",
"digest": "a0de802294717b80e08d9d30f5fd64eacb90b5b3b9d7a0c27d6226a22822597f"
},
{
+ "name": "reversed_hand_with_middle_finger_extended_tone2",
+ "unicode": "1F595-1F3FC",
+ "digest": "a0de802294717b80e08d9d30f5fd64eacb90b5b3b9d7a0c27d6226a22822597f"
+ },
+ {
"name": "middle_finger_tone3",
"unicode": "1F595-1F3FD",
"digest": "8bbbab07c838257416bbf8377904362c07019fca9d5abf9fd048ccf6370178da"
},
{
+ "name": "reversed_hand_with_middle_finger_extended_tone3",
+ "unicode": "1F595-1F3FD",
+ "digest": "8bbbab07c838257416bbf8377904362c07019fca9d5abf9fd048ccf6370178da"
+ },
+ {
"name": "middle_finger_tone4",
"unicode": "1F595-1F3FE",
"digest": "d9eed8db540fdb669c6ae5ef168b77659660589f5ddd9b66062274d335a3ef04"
},
{
+ "name": "reversed_hand_with_middle_finger_extended_tone4",
+ "unicode": "1F595-1F3FE",
+ "digest": "d9eed8db540fdb669c6ae5ef168b77659660589f5ddd9b66062274d335a3ef04"
+ },
+ {
"name": "middle_finger_tone5",
"unicode": "1F595-1F3FF",
"digest": "0519c3298040e57db202294476df239edb9b23b44848bab296bc45eda7cf8664"
},
{
+ "name": "reversed_hand_with_middle_finger_extended_tone5",
+ "unicode": "1F595-1F3FF",
+ "digest": "0519c3298040e57db202294476df239edb9b23b44848bab296bc45eda7cf8664"
+ },
+ {
"name": "military_medal",
"unicode": "1F396",
"digest": "bd1da0004768f404c6bb4db85d4b748f766a77ab3edb74e709d0c0064509a043"
@@ -5110,6 +7055,11 @@
"digest": "3ac2f9b5409e1426eef6966938ca04cf78aeffefd43f44b6c86af4af7836e22f"
},
{
+ "name": "money_mouth_face",
+ "unicode": "1F911",
+ "digest": "3ac2f9b5409e1426eef6966938ca04cf78aeffefd43f44b6c86af4af7836e22f"
+ },
+ {
"name": "money_with_wings",
"unicode": "1F4B8",
"digest": "f7f1fa502d2f6804169869aeb5ca7f0ea64bc2d6a0204f08875d65da4f8cb332"
@@ -5145,11 +7095,21 @@
"digest": "4af3e4e53eaa328b0d20542ab31705a74bf9fd368cd0673b706838ce1681d3c9"
},
{
+ "name": "lightning_mood_bubble",
+ "unicode": "1F5F1",
+ "digest": "4af3e4e53eaa328b0d20542ab31705a74bf9fd368cd0673b706838ce1681d3c9"
+ },
+ {
"name": "mood_lightning",
"unicode": "1F5F2",
"digest": "6784635e81ec722fd50a1c2a23b0f9679e4bf1b5ae2b5a01eeb995bc1f7a426f"
},
{
+ "name": "lightning_mood",
+ "unicode": "1F5F2",
+ "digest": "6784635e81ec722fd50a1c2a23b0f9679e4bf1b5ae2b5a01eeb995bc1f7a426f"
+ },
+ {
"name": "mortar_board",
"unicode": "1F393",
"digest": "cb59edb08f75c374088b65284e4d0f77b9bc9573de3e6a5127f865431011e54c"
@@ -5170,6 +7130,11 @@
"digest": "8429fb6dfeb873abdffcc179c32d4f23e91c9e6b27b06cd204fd2e83cc11189e"
},
{
+ "name": "racing_motorcycle",
+ "unicode": "1F3CD",
+ "digest": "8429fb6dfeb873abdffcc179c32d4f23e91c9e6b27b06cd204fd2e83cc11189e"
+ },
+ {
"name": "motorway",
"unicode": "1F6E3",
"digest": "fc05a36c917637c135b0a60db8afcd58cee2b335070fe3888697f8026c9d11a5"
@@ -5230,6 +7195,11 @@
"digest": "9939aade3d4d972ba3af16fcc6cc2454978f5426e4c92838734a44db065ce0ff"
},
{
+ "name": "snow_capped_mountain",
+ "unicode": "1F3D4",
+ "digest": "9939aade3d4d972ba3af16fcc6cc2454978f5426e4c92838734a44db065ce0ff"
+ },
+ {
"name": "mouse",
"unicode": "1F42D",
"digest": "fb20b3a82f407a6316bbbac68d58018c3d5b93a9a6ae968f44ace18d1c5698d9"
@@ -5245,11 +7215,21 @@
"digest": "e0d2055ccba489d24e0c0b6d2f22793efe48a734b0fd50f5af88f721b40665c0"
},
{
+ "name": "one_button_mouse",
+ "unicode": "1F5AF",
+ "digest": "e0d2055ccba489d24e0c0b6d2f22793efe48a734b0fd50f5af88f721b40665c0"
+ },
+ {
"name": "mouse_three_button",
"unicode": "1F5B1",
"digest": "6a5629fee01145211cc8f4e8f59c5f1e61affed38c650502213d76c7d8861b01"
},
{
+ "name": "three_button_mouse",
+ "unicode": "1F5B1",
+ "digest": "6a5629fee01145211cc8f4e8f59c5f1e61affed38c650502213d76c7d8861b01"
+ },
+ {
"name": "movie_camera",
"unicode": "1F3A5",
"digest": "d6633b89a637b64d617c3032eed74bb82d3fa732dd9975486b2b5841b473808a"
@@ -5365,11 +7345,21 @@
"digest": "94efd551700aae8909b8dd7a78a54a33e070d24b2e0a10534353645084614e98"
},
{
+ "name": "nerd_face",
+ "unicode": "1F913",
+ "digest": "94efd551700aae8909b8dd7a78a54a33e070d24b2e0a10534353645084614e98"
+ },
+ {
"name": "network",
"unicode": "1F5A7",
"digest": "1dbaa54deeb2328fd8a3f044e450c97ac3ff39627c598bb2f4312d677482ee06"
},
{
+ "name": "three_networked_computers",
+ "unicode": "1F5A7",
+ "digest": "1dbaa54deeb2328fd8a3f044e450c97ac3ff39627c598bb2f4312d677482ee06"
+ },
+ {
"name": "neutral_face",
"unicode": "1F610",
"digest": "df01da8501e1f588049c8ed66e504e9abcce83f74ce5790f4d3dc547408f77ee"
@@ -5400,6 +7390,11 @@
"digest": "0ca6b5850091f23295c970815a8e64a52e3c3dae492029ecb1e0726c2693f9bf"
},
{
+ "name": "rolled_up_newspaper",
+ "unicode": "1F5DE",
+ "digest": "0ca6b5850091f23295c970815a8e64a52e3c3dae492029ecb1e0726c2693f9bf"
+ },
+ {
"name": "ng",
"unicode": "1F196",
"digest": "4994c9b795033ed788e98c4af571a1dffe28c0a1479e3b42dcae21bb08381b5f"
@@ -5525,11 +7520,21 @@
"digest": "073660fdaa02ecf98d04f61f8d65d6cc447ccae3825fccaff19a2c99ebba52af"
},
{
+ "name": "note_page",
+ "unicode": "1F5C9",
+ "digest": "073660fdaa02ecf98d04f61f8d65d6cc447ccae3825fccaff19a2c99ebba52af"
+ },
+ {
"name": "note_empty",
"unicode": "1F5C6",
"digest": "06b56eeaca6349bbcf1020bea98f937450a7e086db65cd5d7497748e0fb607be"
},
{
+ "name": "empty_note_page",
+ "unicode": "1F5C6",
+ "digest": "06b56eeaca6349bbcf1020bea98f937450a7e086db65cd5d7497748e0fb607be"
+ },
+ {
"name": "notebook",
"unicode": "1F4D3",
"digest": "64bd4a3e7ca7b22fc704c7b7bd4d13540c16bc69b9d8dd76e69e6ad573ab3823"
@@ -5545,16 +7550,31 @@
"digest": "85069e2d13540886457368a57295072aec44c7137d9223bfcf908ce1f0e5124e"
},
{
+ "name": "note_pad",
+ "unicode": "1F5CA",
+ "digest": "85069e2d13540886457368a57295072aec44c7137d9223bfcf908ce1f0e5124e"
+ },
+ {
"name": "notepad_empty",
"unicode": "1F5C7",
"digest": "8be5053e74c13d8220917c5aee1f4afdecb001612886438f283b0c2a0fecf6af"
},
{
+ "name": "empty_note_pad",
+ "unicode": "1F5C7",
+ "digest": "8be5053e74c13d8220917c5aee1f4afdecb001612886438f283b0c2a0fecf6af"
+ },
+ {
"name": "notepad_spiral",
"unicode": "1F5D2",
"digest": "c181b6c1cc6063ec1848e46cbbf1d8b890c53b59cdc5218311ce06889570e727"
},
{
+ "name": "spiral_note_pad",
+ "unicode": "1F5D2",
+ "digest": "c181b6c1cc6063ec1848e46cbbf1d8b890c53b59cdc5218311ce06889570e727"
+ },
+ {
"name": "notes",
"unicode": "1F3B6",
"digest": "bf3868386e17eac40ac7fbabea027042027ff061daafe406c869cdd8ce94641d"
@@ -5600,6 +7620,11 @@
"digest": "f8b7626cb09e229203105b9c8c7f3fbb38c0650021092fc50115ad517248644a"
},
{
+ "name": "oil_drum",
+ "unicode": "1F6E2",
+ "digest": "f8b7626cb09e229203105b9c8c7f3fbb38c0650021092fc50115ad517248644a"
+ },
+ {
"name": "ok",
"unicode": "1F197",
"digest": "6b05bbab4a7104541c2f4bce553884d17ae0ad07589b19d6b53b6949c14f2269"
@@ -5700,31 +7725,61 @@
"digest": "3ed599443eed25399aac999fc234c9e97f8fb6ec567e37a553c26e01021b097c"
},
{
+ "name": "grandma",
+ "unicode": "1F475",
+ "digest": "3ed599443eed25399aac999fc234c9e97f8fb6ec567e37a553c26e01021b097c"
+ },
+ {
"name": "older_woman_tone1",
"unicode": "1F475-1F3FB",
"digest": "7421c5dba67cfd1eeabb2fa8faf4aa0d615d23f191cf7d7c0ad9c1fa884edfda"
},
{
+ "name": "grandma_tone1",
+ "unicode": "1F475-1F3FB",
+ "digest": "7421c5dba67cfd1eeabb2fa8faf4aa0d615d23f191cf7d7c0ad9c1fa884edfda"
+ },
+ {
"name": "older_woman_tone2",
"unicode": "1F475-1F3FC",
"digest": "65edeef25648ac7f8be535df06af1286441691fa15176e99a6e83fc779aa2cde"
},
{
+ "name": "grandma_tone2",
+ "unicode": "1F475-1F3FC",
+ "digest": "65edeef25648ac7f8be535df06af1286441691fa15176e99a6e83fc779aa2cde"
+ },
+ {
"name": "older_woman_tone3",
"unicode": "1F475-1F3FD",
"digest": "5d27bbcc5796227a9caec1c7612d3f691055655b96f7303e420839463d76c269"
},
{
+ "name": "grandma_tone3",
+ "unicode": "1F475-1F3FD",
+ "digest": "5d27bbcc5796227a9caec1c7612d3f691055655b96f7303e420839463d76c269"
+ },
+ {
"name": "older_woman_tone4",
"unicode": "1F475-1F3FE",
"digest": "75b858e910175fc0233503d672120fd43ac035ba3fd2052fbb44df39f6e3695c"
},
{
+ "name": "grandma_tone4",
+ "unicode": "1F475-1F3FE",
+ "digest": "75b858e910175fc0233503d672120fd43ac035ba3fd2052fbb44df39f6e3695c"
+ },
+ {
"name": "older_woman_tone5",
"unicode": "1F475-1F3FF",
"digest": "9da1cf10a605c470877d7f4a840f99344b1ec2e7b1ec7db61e930cde77025e3b"
},
{
+ "name": "grandma_tone5",
+ "unicode": "1F475-1F3FF",
+ "digest": "9da1cf10a605c470877d7f4a840f99344b1ec2e7b1ec7db61e930cde77025e3b"
+ },
+ {
"name": "om_symbol",
"unicode": "1F549",
"digest": "c8c1c9d445b1fc50a627b71bee21fba978e04532e4685ec032a0174f51fc12bb"
@@ -5810,6 +7865,11 @@
"digest": "df8c10028d29d65f144a6b789d1c3294e7b3293554c4c30d28d72dc7ba8d9a5d"
},
{
+ "name": "optical_disc_icon",
+ "unicode": "1F5B8",
+ "digest": "df8c10028d29d65f144a6b789d1c3294e7b3293554c4c30d28d72dc7ba8d9a5d"
+ },
+ {
"name": "orange_book",
"unicode": "1F4D9",
"digest": "86d150ea3d62183ab7dfe2851cf7f4d1ae769b7ecbb1987b0f463e639e429598"
@@ -5865,6 +7925,11 @@
"digest": "73eb33184f5f495d6c2699fafc1a8680069f82a70fbe519290c3a2ce30d1aee9"
},
{
+ "name": "lower_left_paintbrush",
+ "unicode": "1F58C",
+ "digest": "73eb33184f5f495d6c2699fafc1a8680069f82a70fbe519290c3a2ce30d1aee9"
+ },
+ {
"name": "palm_tree",
"unicode": "1F334",
"digest": "1589ff4b1b87296edc0118e4aa67b3b504ed85a5b8d47e7d0c3e309d0bbf8cd6"
@@ -5885,11 +7950,21 @@
"digest": "7071e031f4a100c3cb3573fbfa375360043f0276289a0818f2ffaf71b3580040"
},
{
+ "name": "linked_paperclips",
+ "unicode": "1F587",
+ "digest": "7071e031f4a100c3cb3573fbfa375360043f0276289a0818f2ffaf71b3580040"
+ },
+ {
"name": "park",
"unicode": "1F3DE",
"digest": "d257f0f1b1a0134573f80ba1a5f522a91c320ee7f93a1cb64877c077e7e19b50"
},
{
+ "name": "national_park",
+ "unicode": "1F3DE",
+ "digest": "d257f0f1b1a0134573f80ba1a5f522a91c320ee7f93a1cb64877c077e7e19b50"
+ },
+ {
"name": "parking",
"unicode": "1F17F",
"digest": "e1d2cfd1c57ea85003ca4df066cbba4e506bf6c4d6c790e27b2f78ad8443fabf"
@@ -5915,11 +7990,21 @@
"digest": "edd605ffaa39a7905ed0958b7cc69f00f5b271e579198d2df1746ad1b3648272"
},
{
+ "name": "double_vertical_bar",
+ "unicode": "23F8",
+ "digest": "edd605ffaa39a7905ed0958b7cc69f00f5b271e579198d2df1746ad1b3648272"
+ },
+ {
"name": "peace",
"unicode": "262E",
"digest": "e0ee8a5c9fb18d5db6841b21527ed8fd955abdff9ffdb7b2684dca22107015fc"
},
{
+ "name": "peace_symbol",
+ "unicode": "262E",
+ "digest": "e0ee8a5c9fb18d5db6841b21527ed8fd955abdff9ffdb7b2684dca22107015fc"
+ },
+ {
"name": "peach",
"unicode": "1F351",
"digest": "a3f4fd5ff02e0a03104ab54456ee1a7521858ee68443856ee10e0972e5b6aaa5"
@@ -5935,16 +8020,31 @@
"digest": "6becdc6f622c774bb09b7e7592bba2123ecccc9de32a35f0b18b50d7d54109cb"
},
{
+ "name": "lower_left_ballpoint_pen",
+ "unicode": "1F58A",
+ "digest": "6becdc6f622c774bb09b7e7592bba2123ecccc9de32a35f0b18b50d7d54109cb"
+ },
+ {
"name": "pen_fountain",
"unicode": "1F58B",
"digest": "8c78cf0c2bd1d5e309d2d3356ff207e3fc76ca18dd6b90762cb62f6afbc95c6a"
},
{
+ "name": "lower_left_fountain_pen",
+ "unicode": "1F58B",
+ "digest": "8c78cf0c2bd1d5e309d2d3356ff207e3fc76ca18dd6b90762cb62f6afbc95c6a"
+ },
+ {
"name": "pencil",
"unicode": "1F4DD",
"digest": "62b7ee5d9352114d09ee6f2c9a4c5e8b79f775a6c509e82ddfcdd61e13716249"
},
{
+ "name": "memo",
+ "unicode": "1F4DD",
+ "digest": "62b7ee5d9352114d09ee6f2c9a4c5e8b79f775a6c509e82ddfcdd61e13716249"
+ },
+ {
"name": "pencil2",
"unicode": "270F",
"digest": "aa2c572772187fee1f9125bb0950f5ce8a61f7dd2647258c40b4077ee5feb498"
@@ -5955,6 +8055,11 @@
"digest": "52c1ba1228917eb491ac1745a495e0fdafba6b985a81caba250f71d1f94c725c"
},
{
+ "name": "lower_left_pencil",
+ "unicode": "1F589",
+ "digest": "52c1ba1228917eb491ac1745a495e0fdafba6b985a81caba250f71d1f94c725c"
+ },
+ {
"name": "penguin",
"unicode": "1F427",
"digest": "095de34b3f6a2521a342c21f5f2551a0092bf47429801c15b7bbf0913924f412"
@@ -5965,11 +8070,21 @@
"digest": "cd3c33bfc3c7fbe84b98d2d481d56a7bf5488ff94afadd8b5a0e454768b80269"
},
{
+ "name": "black_pennant",
+ "unicode": "1F3F2",
+ "digest": "cd3c33bfc3c7fbe84b98d2d481d56a7bf5488ff94afadd8b5a0e454768b80269"
+ },
+ {
"name": "pennant_white",
"unicode": "1F3F1",
"digest": "818b1be73540f2cfeb1c514e1ee75d18715af317f0db817d9ae081b9ea33d4b0"
},
{
+ "name": "white_pennant",
+ "unicode": "1F3F1",
+ "digest": "818b1be73540f2cfeb1c514e1ee75d18715af317f0db817d9ae081b9ea33d4b0"
+ },
+ {
"name": "pensive",
"unicode": "1F614",
"digest": "2d9e7f1eed14dcc86674cec78e992567a40d0f223fc67d722b91eebcd1251269"
@@ -6110,11 +8225,21 @@
"digest": "dd2a84716c93410a285ff759bfbc2dc31a10f90b203c7a657b908e5949e89a39"
},
{
+ "name": "table_tennis",
+ "unicode": "1F3D3",
+ "digest": "dd2a84716c93410a285ff759bfbc2dc31a10f90b203c7a657b908e5949e89a39"
+ },
+ {
"name": "piracy",
"unicode": "1F572",
"digest": "f42955ba75c598392e5e258be49968d858c876e0d6e7aa9dc795f7e8cff42be9"
},
{
+ "name": "no_piracy",
+ "unicode": "1F572",
+ "digest": "f42955ba75c598392e5e258be49968d858c876e0d6e7aa9dc795f7e8cff42be9"
+ },
+ {
"name": "pisces",
"unicode": "2653",
"digest": "75f11b9a094196b54a242420362fa7c0aeba7cfc497b187e1aaaba96d93684a7"
@@ -6130,6 +8255,11 @@
"digest": "4fabc307b7e35f94288f6d53985485662a4814b11a9a382f0a3873d41b1290d3"
},
{
+ "name": "worship_symbol",
+ "unicode": "1F6D0",
+ "digest": "4fabc307b7e35f94288f6d53985485662a4814b11a9a382f0a3873d41b1290d3"
+ },
+ {
"name": "play_pause",
"unicode": "23EF",
"digest": "d69e8cdec33447283cf65d343b986115e27681d781b721db7894e5c587ca18ad"
@@ -6300,6 +8430,21 @@
"digest": "140ce75a015ede5e764873e0ae9a56e7b2af333eddca0fe2796b14545c620258"
},
{
+ "name": "shit",
+ "unicode": "1F4A9",
+ "digest": "140ce75a015ede5e764873e0ae9a56e7b2af333eddca0fe2796b14545c620258"
+ },
+ {
+ "name": "hankey",
+ "unicode": "1F4A9",
+ "digest": "140ce75a015ede5e764873e0ae9a56e7b2af333eddca0fe2796b14545c620258"
+ },
+ {
+ "name": "poo",
+ "unicode": "1F4A9",
+ "digest": "140ce75a015ede5e764873e0ae9a56e7b2af333eddca0fe2796b14545c620258"
+ },
+ {
"name": "popcorn",
"unicode": "1F37F",
"digest": "12264cb16fca9317e3ba8d5924a2c8f15f790e36d2f29e7b12aaaf77e1beb73d"
@@ -6420,11 +8565,21 @@
"digest": "bc6cdea2269a0ec39576d98dc4cda2bd9efa4dc330dde870148c6a85ad9cc63f"
},
{
+ "name": "prohibited_sign",
+ "unicode": "1F6C7",
+ "digest": "bc6cdea2269a0ec39576d98dc4cda2bd9efa4dc330dde870148c6a85ad9cc63f"
+ },
+ {
"name": "projector",
"unicode": "1F4FD",
"digest": "fc361282f367926254c08150b02cb8fda7fa8d2c9c939d9360c78bf19a4f982e"
},
{
+ "name": "film_projector",
+ "unicode": "1F4FD",
+ "digest": "fc361282f367926254c08150b02cb8fda7fa8d2c9c939d9360c78bf19a4f982e"
+ },
+ {
"name": "punch",
"unicode": "1F44A",
"digest": "5759db1d7093744c74b840bbb4761fb025d6633f8fa539bcb35dcf54fc05ceb6"
@@ -6500,6 +8655,11 @@
"digest": "2e9828e3884c79ad7e9e1173d3470790f3f56cfa08ef4e38deff45db0728c66c"
},
{
+ "name": "racing_car",
+ "unicode": "1F3CE",
+ "digest": "2e9828e3884c79ad7e9e1173d3470790f3f56cfa08ef4e38deff45db0728c66c"
+ },
+ {
"name": "racehorse",
"unicode": "1F40E",
"digest": "36aa3c7123ee7e15600657166032b21b8edeb192cf6d3ada39b5c65001f7fc40"
@@ -6520,6 +8680,11 @@
"digest": "5ad8e8594617c0153672a76421deb836e05c6098020c33af3f975f8fcfe216e4"
},
{
+ "name": "radioactive_sign",
+ "unicode": "2622",
+ "digest": "5ad8e8594617c0153672a76421deb836e05c6098020c33af3f975f8fcfe216e4"
+ },
+ {
"name": "rage",
"unicode": "1F621",
"digest": "02ac70551fc51478884c133b29539cae58b463c760db38c0aeec1bdf5b282312"
@@ -6535,6 +8700,11 @@
"digest": "63ee881cc775d5b2711082b6c96ab44d5204c5d390afd6d8ee97e52aeeaa5e5e"
},
{
+ "name": "railroad_track",
+ "unicode": "1F6E4",
+ "digest": "63ee881cc775d5b2711082b6c96ab44d5204c5d390afd6d8ee97e52aeeaa5e5e"
+ },
+ {
"name": "rainbow",
"unicode": "1F308",
"digest": "bbd8ecc8d0737948969a3539d2d202e599404e509f1a21bdbb0a0c41c2540522"
@@ -6745,11 +8915,21 @@
"digest": "5b92daa87bdf6ee15e798bec382a2ee885f4e6e77a68a3f626adcfe4c782b375"
},
{
+ "name": "right_speaker_with_one_sound_wave",
+ "unicode": "1F569",
+ "digest": "5b92daa87bdf6ee15e798bec382a2ee885f4e6e77a68a3f626adcfe4c782b375"
+ },
+ {
"name": "right_speaker_three",
"unicode": "1F56A",
"digest": "4d00b720a65bd0f4c3682b290b1976ec2388d6ae61225398f4e70556ae9e5f80"
},
{
+ "name": "right_speaker_with_three_sound_waves",
+ "unicode": "1F56A",
+ "digest": "4d00b720a65bd0f4c3682b290b1976ec2388d6ae61225398f4e70556ae9e5f80"
+ },
+ {
"name": "ring",
"unicode": "1F48D",
"digest": "ae2a93e7895b9b89f5a39f01d356ffed988f219ef8b658a56c55285826a4533b"
@@ -6765,6 +8945,11 @@
"digest": "cc0e363774b86e21a5b2cea7f7af85bca9e92c124ebcd39c6067c125048baa60"
},
{
+ "name": "robot_face",
+ "unicode": "1F916",
+ "digest": "cc0e363774b86e21a5b2cea7f7af85bca9e92c124ebcd39c6067c125048baa60"
+ },
+ {
"name": "rocket",
"unicode": "1F680",
"digest": "65d8bd005ceac41904237b7a8c5f55f16713a55d971522f0bbe63a1d548e515d"
@@ -6780,6 +8965,11 @@
"digest": "f596f203030b6c9bd743848512aa3fc7919447020d35ae5c2bf13ccb16fa2dbe"
},
{
+ "name": "face_with_rolling_eyes",
+ "unicode": "1F644",
+ "digest": "f596f203030b6c9bd743848512aa3fc7919447020d35ae5c2bf13ccb16fa2dbe"
+ },
+ {
"name": "rooster",
"unicode": "1F413",
"digest": "6cefdaa45631ed8c9480e15f578c793d95af81b42687164fd7900eee325ccf07"
@@ -7100,11 +9290,21 @@
"digest": "dfd169764b192ac7c6e5101277dd9f1e010e86bdd32ad37e00ed4499fc0a5dd6"
},
{
+ "name": "skeleton",
+ "unicode": "1F480",
+ "digest": "dfd169764b192ac7c6e5101277dd9f1e010e86bdd32ad37e00ed4499fc0a5dd6"
+ },
+ {
"name": "skull_crossbones",
"unicode": "2620",
"digest": "e2acf0f36b6a6800c1829a1c6551b5d0eb6dcdef4b7f02070cf69570aeab608c"
},
{
+ "name": "skull_and_crossbones",
+ "unicode": "2620",
+ "digest": "e2acf0f36b6a6800c1829a1c6551b5d0eb6dcdef4b7f02070cf69570aeab608c"
+ },
+ {
"name": "sleeping",
"unicode": "1F634",
"digest": "4ead95079b1a542eedd0e5a0e93fddb318a002bdaffaa2fe5d8d7f20bf8143ed"
@@ -7125,11 +9325,21 @@
"digest": "3ae82b38b58ffa50eddebd87153428d880ca181f4f4178a9ca3bd813ea15ccbc"
},
{
+ "name": "slightly_frowning_face",
+ "unicode": "1F641",
+ "digest": "3ae82b38b58ffa50eddebd87153428d880ca181f4f4178a9ca3bd813ea15ccbc"
+ },
+ {
"name": "slight_smile",
"unicode": "1F642",
"digest": "5eee09f634a4e2031927d008a6530a258a00e611ead0c386dd5b7ebb5e75a306"
},
{
+ "name": "slightly_smiling_face",
+ "unicode": "1F642",
+ "digest": "5eee09f634a4e2031927d008a6530a258a00e611ead0c386dd5b7ebb5e75a306"
+ },
+ {
"name": "slot_machine",
"unicode": "1F3B0",
"digest": "9d516b389299431b608c89d3f02ac68d28cb8df2a780f2048923bbcfbb49f416"
@@ -7300,6 +9510,11 @@
"digest": "d92cfe1200887300b2f05f9576448a2f2a79d0accd51f323a65ce3db0aa5639b"
},
{
+ "name": "speaking_head_in_silhouette",
+ "unicode": "1F5E3",
+ "digest": "d92cfe1200887300b2f05f9576448a2f2a79d0accd51f323a65ce3db0aa5639b"
+ },
+ {
"name": "speech_balloon",
"unicode": "1F4AC",
"digest": "5dccfda46fc984583bc9eaece66e7e884f2a9eb12a69dbd3493035e3c862edd0"
@@ -7310,21 +9525,41 @@
"digest": "478b0b07460a9f54b7d0050f886da59fde5e428daa11e899fc31477fda1707ed"
},
{
+ "name": "left_speech_bubble",
+ "unicode": "1F5E8",
+ "digest": "478b0b07460a9f54b7d0050f886da59fde5e428daa11e899fc31477fda1707ed"
+ },
+ {
"name": "speech_right",
"unicode": "1F5E9",
"digest": "8439b13779163c15e678a78b08ebeeb7d131632df21d2a7868de7fed38ca9d8a"
},
{
+ "name": "right_speech_bubble",
+ "unicode": "1F5E9",
+ "digest": "8439b13779163c15e678a78b08ebeeb7d131632df21d2a7868de7fed38ca9d8a"
+ },
+ {
"name": "speech_three",
"unicode": "1F5EB",
"digest": "55a934f3659b6e75fdce0d0c4e2ea56dd34a43892c85a6666bd1882a0bfb92a9"
},
{
+ "name": "three_speech_bubbles",
+ "unicode": "1F5EB",
+ "digest": "55a934f3659b6e75fdce0d0c4e2ea56dd34a43892c85a6666bd1882a0bfb92a9"
+ },
+ {
"name": "speech_two",
"unicode": "1F5EA",
"digest": "0563ef0591da243673cf877462acc5d8e1d980a56e81668ac627de74d0c33983"
},
{
+ "name": "two_speech_bubbles",
+ "unicode": "1F5EA",
+ "digest": "0563ef0591da243673cf877462acc5d8e1d980a56e81668ac627de74d0c33983"
+ },
+ {
"name": "speedboat",
"unicode": "1F6A4",
"digest": "553a288ab8eeb3dee7b9d1c92eba38016caef7658beaa828136ba1d6ba8ed08a"
@@ -7345,31 +9580,61 @@
"digest": "eaa570a36d83119d0a596228e74affe84d7355714ff6901d88a89410d26dec2a"
},
{
+ "name": "sleuth_or_spy",
+ "unicode": "1F575",
+ "digest": "eaa570a36d83119d0a596228e74affe84d7355714ff6901d88a89410d26dec2a"
+ },
+ {
"name": "spy_tone1",
"unicode": "1F575-1F3FB",
"digest": "abdc066d4cad6a17047faf7806c45feb43ae1e2056cf500536f08f4173dbfa94"
},
{
+ "name": "sleuth_or_spy_tone1",
+ "unicode": "1F575-1F3FB",
+ "digest": "abdc066d4cad6a17047faf7806c45feb43ae1e2056cf500536f08f4173dbfa94"
+ },
+ {
"name": "spy_tone2",
"unicode": "1F575-1F3FC",
"digest": "72a3313ef12364105e764cc3deabd47eb6bd086f261c435682ae1cd29dc8230b"
},
{
+ "name": "sleuth_or_spy_tone2",
+ "unicode": "1F575-1F3FC",
+ "digest": "72a3313ef12364105e764cc3deabd47eb6bd086f261c435682ae1cd29dc8230b"
+ },
+ {
"name": "spy_tone3",
"unicode": "1F575-1F3FD",
"digest": "2a1108d3d2e778f88aa5b3ae36705c877b84d0bf6b421409582ba748aeb2aee7"
},
{
+ "name": "sleuth_or_spy_tone3",
+ "unicode": "1F575-1F3FD",
+ "digest": "2a1108d3d2e778f88aa5b3ae36705c877b84d0bf6b421409582ba748aeb2aee7"
+ },
+ {
"name": "spy_tone4",
"unicode": "1F575-1F3FE",
"digest": "1d4fe62912384bc0d687bcf4565752caf0ed6146c903a156d1c6ba6ea239b154"
},
{
+ "name": "sleuth_or_spy_tone4",
+ "unicode": "1F575-1F3FE",
+ "digest": "1d4fe62912384bc0d687bcf4565752caf0ed6146c903a156d1c6ba6ea239b154"
+ },
+ {
"name": "spy_tone5",
"unicode": "1F575-1F3FF",
"digest": "69c1baac73783edb9e2d0c951f922dc7dddac34d0a9c818fee8d1021bc17db0d"
},
{
+ "name": "sleuth_or_spy_tone5",
+ "unicode": "1F575-1F3FF",
+ "digest": "69c1baac73783edb9e2d0c951f922dc7dddac34d0a9c818fee8d1021bc17db0d"
+ },
+ {
"name": "stadium",
"unicode": "1F3DF",
"digest": "4356db5d2cdef8c40830638debaf1f50831130c12ae8d8dc3d9a6bd28fdaa1f7"
@@ -7420,6 +9685,11 @@
"digest": "1ce1f9a83867514b8351ad4fd80c46bba04ad67dfb9874e63d7296e1a21161a5"
},
{
+ "name": "portable_stereo",
+ "unicode": "1F4FE",
+ "digest": "1ce1f9a83867514b8351ad4fd80c46bba04ad67dfb9874e63d7296e1a21161a5"
+ },
+ {
"name": "stew",
"unicode": "1F372",
"digest": "12e6e4bf48a7296700e07a053d831dd67b70c308ca9522ca96e933a4d1ef6c5e"
@@ -7645,6 +9915,11 @@
"digest": "c3a42a653a91d90c6b668f678419d5438f2e546050914b841623e57107e805db"
},
{
+ "name": "black_touchtone_telephone",
+ "unicode": "1F57F",
+ "digest": "c3a42a653a91d90c6b668f678419d5438f2e546050914b841623e57107e805db"
+ },
+ {
"name": "telephone_receiver",
"unicode": "1F4DE",
"digest": "e3bf6034de6cf2160893ba4990eba198185a6a3f9cd5767a63b048e41c297640"
@@ -7655,6 +9930,11 @@
"digest": "62a7e0e50c53e9f85eba51a92882e6064be05997910d3f7700e1e957dbaf0581"
},
{
+ "name": "white_touchtone_telephone",
+ "unicode": "1F57E",
+ "digest": "62a7e0e50c53e9f85eba51a92882e6064be05997910d3f7700e1e957dbaf0581"
+ },
+ {
"name": "telescope",
"unicode": "1F52D",
"digest": "abe0aca5f2c78105b0e9e4c8ee7a40adcd9bb013e7c49d568076459bade73556"
@@ -7685,11 +9965,21 @@
"digest": "f19c489d89dd2d39770a6c8725a20f3e98f9e5216774af60c0665fd6a03a7687"
},
{
+ "name": "face_with_thermometer",
+ "unicode": "1F912",
+ "digest": "f19c489d89dd2d39770a6c8725a20f3e98f9e5216774af60c0665fd6a03a7687"
+ },
+ {
"name": "thinking",
"unicode": "1F914",
"digest": "f64a9a18dca4c502b46f933838753a818b604a9d0268aa32eda26cbd31abc58c"
},
{
+ "name": "thinking_face",
+ "unicode": "1F914",
+ "digest": "f64a9a18dca4c502b46f933838753a818b604a9d0268aa32eda26cbd31abc58c"
+ },
+ {
"name": "thought_balloon",
"unicode": "1F4AD",
"digest": "76c8513191641f0a79e878ccc0d83c4576984609810633f596db2f64cc684b7d"
@@ -7700,11 +9990,21 @@
"digest": "4fd591bf4318df73d1b17f434a449d8e95f49cca53a3d8f4d1ca983f3809ef46"
},
{
+ "name": "left_thought_bubble",
+ "unicode": "1F5EC",
+ "digest": "4fd591bf4318df73d1b17f434a449d8e95f49cca53a3d8f4d1ca983f3809ef46"
+ },
+ {
"name": "thought_right",
"unicode": "1F5ED",
"digest": "0e8c0ce26e2d0e30894f5394b0736456e8268f775e0e7eda4c7dc3c2ff9231ae"
},
{
+ "name": "right_thought_bubble",
+ "unicode": "1F5ED",
+ "digest": "0e8c0ce26e2d0e30894f5394b0736456e8268f775e0e7eda4c7dc3c2ff9231ae"
+ },
+ {
"name": "three",
"unicode": "0033-20E3",
"digest": "ca0147a8f67cea3bc2516fa8deef4325188359559786c94ff0b27f90eef04b88"
@@ -7715,76 +10015,151 @@
"digest": "a8b561e389bc4e4b07fba70994f6445e5ddc6afe68922fcb6e9e7282d19ad958"
},
{
+ "name": "reversed_thumbs_down_sign",
+ "unicode": "1F593",
+ "digest": "a8b561e389bc4e4b07fba70994f6445e5ddc6afe68922fcb6e9e7282d19ad958"
+ },
+ {
"name": "thumbs_up_reverse",
"unicode": "1F592",
"digest": "b6e52715c5ce590bfd08f6e05058ec3765ea2da341b11f9825d100608b173837"
},
{
+ "name": "reversed_thumbs_up_sign",
+ "unicode": "1F592",
+ "digest": "b6e52715c5ce590bfd08f6e05058ec3765ea2da341b11f9825d100608b173837"
+ },
+ {
"name": "thumbsdown",
"unicode": "1F44E",
"digest": "a98f742c9773e0d95c0de5e1c10d1ab373fa761378a205f27d095e85debe69a3"
},
{
+ "name": "-1",
+ "unicode": "1F44E",
+ "digest": "a98f742c9773e0d95c0de5e1c10d1ab373fa761378a205f27d095e85debe69a3"
+ },
+ {
"name": "thumbsdown_tone1",
"unicode": "1F44E-1F3FB",
"digest": "5d0a7c63d52eafe6267c552168c5557a66622009d565c3cf7b5378c1f6e84bce"
},
{
+ "name": "-1_tone1",
+ "unicode": "1F44E-1F3FB",
+ "digest": "5d0a7c63d52eafe6267c552168c5557a66622009d565c3cf7b5378c1f6e84bce"
+ },
+ {
"name": "thumbsdown_tone2",
"unicode": "1F44E-1F3FC",
"digest": "ca5c15dc516660b2989a1c717bf3745fdfb6964c7acf3b938285ff6c7caf2ca2"
},
{
+ "name": "-1_tone2",
+ "unicode": "1F44E-1F3FC",
+ "digest": "ca5c15dc516660b2989a1c717bf3745fdfb6964c7acf3b938285ff6c7caf2ca2"
+ },
+ {
"name": "thumbsdown_tone3",
"unicode": "1F44E-1F3FD",
"digest": "05740e3568795270674dac9134198bf75b1b778c11daa71649c88c231859ec16"
},
{
+ "name": "-1_tone3",
+ "unicode": "1F44E-1F3FD",
+ "digest": "05740e3568795270674dac9134198bf75b1b778c11daa71649c88c231859ec16"
+ },
+ {
"name": "thumbsdown_tone4",
"unicode": "1F44E-1F3FE",
"digest": "5ee93bcc2f515806462a7b303064beade2b22a3f43a8162e39fd65d15d772e27"
},
{
+ "name": "-1_tone4",
+ "unicode": "1F44E-1F3FE",
+ "digest": "5ee93bcc2f515806462a7b303064beade2b22a3f43a8162e39fd65d15d772e27"
+ },
+ {
"name": "thumbsdown_tone5",
"unicode": "1F44E-1F3FF",
"digest": "5c9ef8d53cf6f755668ab6dabfbfcdfd4b95fd59db3b3dd60290efefe9c33994"
},
{
+ "name": "-1_tone5",
+ "unicode": "1F44E-1F3FF",
+ "digest": "5c9ef8d53cf6f755668ab6dabfbfcdfd4b95fd59db3b3dd60290efefe9c33994"
+ },
+ {
"name": "thumbsup",
"unicode": "1F44D",
"digest": "28b31df963773ba42a1a089f43cd89d0ce1ab0981e5410f41242e9a125fc1aee"
},
{
+ "name": "+1",
+ "unicode": "1F44D",
+ "digest": "28b31df963773ba42a1a089f43cd89d0ce1ab0981e5410f41242e9a125fc1aee"
+ },
+ {
"name": "thumbsup_tone1",
"unicode": "1F44D-1F3FB",
"digest": "f6365942738d2128b6959d6672b3d295757dc8240703cb84a2b014ad78d67de3"
},
{
+ "name": "+1_tone1",
+ "unicode": "1F44D-1F3FB",
+ "digest": "f6365942738d2128b6959d6672b3d295757dc8240703cb84a2b014ad78d67de3"
+ },
+ {
"name": "thumbsup_tone2",
"unicode": "1F44D-1F3FC",
"digest": "771d30146e4dc947a69057b05d32c765c8457ab02b5342889c5489acf27ef356"
},
{
+ "name": "+1_tone2",
+ "unicode": "1F44D-1F3FC",
+ "digest": "771d30146e4dc947a69057b05d32c765c8457ab02b5342889c5489acf27ef356"
+ },
+ {
"name": "thumbsup_tone3",
"unicode": "1F44D-1F3FD",
"digest": "0bb7bbfb654c6139260e1786e7ffa5a33f31e19410c1d4d15737fdf5dd4c721d"
},
{
+ "name": "+1_tone3",
+ "unicode": "1F44D-1F3FD",
+ "digest": "0bb7bbfb654c6139260e1786e7ffa5a33f31e19410c1d4d15737fdf5dd4c721d"
+ },
+ {
"name": "thumbsup_tone4",
"unicode": "1F44D-1F3FE",
"digest": "df0927c5342f0075fbf4ea83b724e6f70c0466c54769c9ce4a5c2deb602b28aa"
},
{
+ "name": "+1_tone4",
+ "unicode": "1F44D-1F3FE",
+ "digest": "df0927c5342f0075fbf4ea83b724e6f70c0466c54769c9ce4a5c2deb602b28aa"
+ },
+ {
"name": "thumbsup_tone5",
"unicode": "1F44D-1F3FF",
"digest": "0683ae08c50aaf186c6406680a60617679c7b4bccd0817f24b15911dbb06866f"
},
{
+ "name": "+1_tone5",
+ "unicode": "1F44D-1F3FF",
+ "digest": "0683ae08c50aaf186c6406680a60617679c7b4bccd0817f24b15911dbb06866f"
+ },
+ {
"name": "thunder_cloud_rain",
"unicode": "26C8",
"digest": "dd836f06b41a10d6ed9bcbdae291d2886847ff66dc3ede2427382e469f60674c"
},
{
+ "name": "thunder_cloud_and_rain",
+ "unicode": "26C8",
+ "digest": "dd836f06b41a10d6ed9bcbdae291d2886847ff66dc3ede2427382e469f60674c"
+ },
+ {
"name": "ticket",
"unicode": "1F3AB",
"digest": "a7654a5529535120da3c377e72cd1f7997bdc2dabf1d44b584f7df7852b158f9"
@@ -7795,6 +10170,11 @@
"digest": "ccafcc9583a84e847ff1eaa3d53187c5ab150a7d27c6a19363e59b9bc046b567"
},
{
+ "name": "admission_tickets",
+ "unicode": "1F39F",
+ "digest": "ccafcc9583a84e847ff1eaa3d53187c5ab150a7d27c6a19363e59b9bc046b567"
+ },
+ {
"name": "tiger",
"unicode": "1F42F",
"digest": "9ebe3117f5f1b589ff8164f8d87dcc275923e0db87121d2cee0fdb9b56dfc4ac"
@@ -7810,6 +10190,11 @@
"digest": "c48199312ed42ff53a33bb2791db19e2e2521223cd49d8f758ea95b9b379c5ff"
},
{
+ "name": "timer_clock",
+ "unicode": "23F2",
+ "digest": "c48199312ed42ff53a33bb2791db19e2e2521223cd49d8f758ea95b9b379c5ff"
+ },
+ {
"name": "tired_face",
"unicode": "1F62B",
"digest": "ad687a956388ec53ca1e301a0abe2f1e2cfb9f73cd543dd61a21c7335a42e332"
@@ -7870,6 +10255,11 @@
"digest": "9b0a36dfdb475621d326359662b22cbdb80563c4f476aa5e7d7c00cdba605bd9"
},
{
+ "name": "hammer_and_wrench",
+ "unicode": "1F6E0",
+ "digest": "9b0a36dfdb475621d326359662b22cbdb80563c4f476aa5e7d7c00cdba605bd9"
+ },
+ {
"name": "top",
"unicode": "1F51D",
"digest": "d645030099aeb433307569e8e1c4342c1c411a8fefe50fdca7a3207a1a0db671"
@@ -7885,11 +10275,21 @@
"digest": "d5415ed140933f345fea8023a3d8fca30dcfcf7d19d9dc9771fa2cae9df62a3b"
},
{
+ "name": "next_track",
+ "unicode": "23ED",
+ "digest": "d5415ed140933f345fea8023a3d8fca30dcfcf7d19d9dc9771fa2cae9df62a3b"
+ },
+ {
"name": "track_previous",
"unicode": "23EE",
"digest": "97ff4a59a236e5cf506fa3577b20715b3b0197e0f343a50615b36185d5b835f1"
},
{
+ "name": "previous_track",
+ "unicode": "23EE",
+ "digest": "97ff4a59a236e5cf506fa3577b20715b3b0197e0f343a50615b36185d5b835f1"
+ },
+ {
"name": "trackball",
"unicode": "1F5B2",
"digest": "8332503454ce42059d720c285fe2b15eb0562a0a4b234dccb0f3159bb30a91aa"
@@ -7920,6 +10320,11 @@
"digest": "621bb967cd93fa9f8fd4b155965cc7572d3f91f88d94938ba10c8626718b623c"
},
{
+ "name": "diesel_locomotive",
+ "unicode": "1F6F2",
+ "digest": "621bb967cd93fa9f8fd4b155965cc7572d3f91f88d94938ba10c8626718b623c"
+ },
+ {
"name": "tram",
"unicode": "1F68A",
"digest": "5a86d31f7ab677d967fecd75babc900b5169766d0228961912314c4c4d1d64ee"
@@ -7930,6 +10335,11 @@
"digest": "e24bb39ecfaaa746b03dc8418697d09ef327d5b077db39014f39d5fb87e23bd5"
},
{
+ "name": "triangle_with_rounded_corners",
+ "unicode": "1F6C6",
+ "digest": "e24bb39ecfaaa746b03dc8418697d09ef327d5b077db39014f39d5fb87e23bd5"
+ },
+ {
"name": "triangular_flag_on_post",
"unicode": "1F6A9",
"digest": "d824c973d84cd62c845d64e546de87b094fda8f9972b6a33acd75e1a5ac19f75"
@@ -7995,6 +10405,11 @@
"digest": "8a6c5b7d4c737866e7e32c6d9f7f447a48a0ac57a8909d43f87367d4a9b59246"
},
{
+ "name": "turned_ok_hand_sign",
+ "unicode": "1F58F",
+ "digest": "8a6c5b7d4c737866e7e32c6d9f7f447a48a0ac57a8909d43f87367d4a9b59246"
+ },
+ {
"name": "turtle",
"unicode": "1F422",
"digest": "388b3e75b931638a09f65b842d26e2cc87b200ba782dec871f84cddd71aaeaf3"
@@ -8110,6 +10525,11 @@
"digest": "1b1e9c209dabe619db76fd346c3fb51b28ace0e4102697fe0973fe2d46aa9f08"
},
{
+ "name": "unicorn_face",
+ "unicode": "1F984",
+ "digest": "1b1e9c209dabe619db76fd346c3fb51b28ace0e4102697fe0973fe2d46aa9f08"
+ },
+ {
"name": "unlock",
"unicode": "1F513",
"digest": "63dbef0855399254ae01cf4ef0676adebc1432ae1ee260b569c23ae8152deaf8"
@@ -8125,11 +10545,21 @@
"digest": "763fe2baf07a9b04f96958adf38a43c7dd2bc70d57398f49604307bd835cbb53"
},
{
+ "name": "upside_down_face",
+ "unicode": "1F643",
+ "digest": "763fe2baf07a9b04f96958adf38a43c7dd2bc70d57398f49604307bd835cbb53"
+ },
+ {
"name": "urn",
"unicode": "26B1",
"digest": "dbfd5b90709d1b812d2fff71a5cfa10f84a4579866c2d7cd0e80759a22b2ba0e"
},
{
+ "name": "funeral_urn",
+ "unicode": "26B1",
+ "digest": "dbfd5b90709d1b812d2fff71a5cfa10f84a4579866c2d7cd0e80759a22b2ba0e"
+ },
+ {
"name": "v",
"unicode": "270C",
"digest": "df85ad1a3ff365c3232a010701c9b25cd824d19fa2511422dee60ac231f457e3"
@@ -8215,31 +10645,61 @@
"digest": "ca800fce797e652c5f47bf44992e8fbe19554688a36423fdf7c29ca6defae1e0"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers",
+ "unicode": "1F596",
+ "digest": "ca800fce797e652c5f47bf44992e8fbe19554688a36423fdf7c29ca6defae1e0"
+ },
+ {
"name": "vulcan_tone1",
"unicode": "1F596-1F3FB",
"digest": "84bafdaca43426b053f5caa4e868ca109d99113a28ea9799db09d3c5d5f645c8"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers_tone1",
+ "unicode": "1F596-1F3FB",
+ "digest": "84bafdaca43426b053f5caa4e868ca109d99113a28ea9799db09d3c5d5f645c8"
+ },
+ {
"name": "vulcan_tone2",
"unicode": "1F596-1F3FC",
"digest": "e7cedf63ead957ee5c287e4cb0828ba70673e17b604f92b529875c32d094e7e3"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers_tone2",
+ "unicode": "1F596-1F3FC",
+ "digest": "e7cedf63ead957ee5c287e4cb0828ba70673e17b604f92b529875c32d094e7e3"
+ },
+ {
"name": "vulcan_tone3",
"unicode": "1F596-1F3FD",
"digest": "e124fef20f289921553274cf834f6dcc1a012889d30d9874dc5ad01afb8235b8"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers_tone3",
+ "unicode": "1F596-1F3FD",
+ "digest": "e124fef20f289921553274cf834f6dcc1a012889d30d9874dc5ad01afb8235b8"
+ },
+ {
"name": "vulcan_tone4",
"unicode": "1F596-1F3FE",
"digest": "ea2115f549e4680467521bbf362b229f4a8f0fdadbfaf231378d801f9b369f08"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers_tone4",
+ "unicode": "1F596-1F3FE",
+ "digest": "ea2115f549e4680467521bbf362b229f4a8f0fdadbfaf231378d801f9b369f08"
+ },
+ {
"name": "vulcan_tone5",
"unicode": "1F596-1F3FF",
"digest": "1b322e1252491f35ae02f0b279b6529dad867f2a6b3c2c3e77f981bed07e447d"
},
{
+ "name": "raised_hand_with_part_between_middle_and_ring_fingers_tone5",
+ "unicode": "1F596-1F3FF",
+ "digest": "1b322e1252491f35ae02f0b279b6529dad867f2a6b3c2c3e77f981bed07e447d"
+ },
+ {
"name": "walking",
"unicode": "1F6B6",
"digest": "8ec0b2207d4368422261bc58944c17dff2554b2356becfb18f21dd87425cd67b"
@@ -8430,16 +10890,31 @@
"digest": "d8ce416e6bdb0e59e06e2fceac3177dbe59fefc248fd8c6d76b80d1418141070"
},
{
+ "name": "white_sun_behind_cloud",
+ "unicode": "1F325",
+ "digest": "d8ce416e6bdb0e59e06e2fceac3177dbe59fefc248fd8c6d76b80d1418141070"
+ },
+ {
"name": "white_sun_rain_cloud",
"unicode": "1F326",
"digest": "d2b132518261864ac4a95707eaeea335dd8351ed2b8ef4e2272ced456e309bf1"
},
{
+ "name": "white_sun_behind_cloud_with_rain",
+ "unicode": "1F326",
+ "digest": "d2b132518261864ac4a95707eaeea335dd8351ed2b8ef4e2272ced456e309bf1"
+ },
+ {
"name": "white_sun_small_cloud",
"unicode": "1F324",
"digest": "b86a72f1cdb4d24fd3ab180aae9db012ca51fc01f3786aab596c2e330066b185"
},
{
+ "name": "white_sun_with_small_cloud",
+ "unicode": "1F324",
+ "digest": "b86a72f1cdb4d24fd3ab180aae9db012ca51fc01f3786aab596c2e330066b185"
+ },
+ {
"name": "wind_blowing_face",
"unicode": "1F32C",
"digest": "20bdeb8e39dc637792ac9fbee031c5791889f3126e83556ba51f98809c19763c"
@@ -8525,6 +11000,11 @@
"digest": "c4fc18ece6778339ebe14438aaf570e22385c3010c2d341824fa72ac6068cfeb"
},
{
+ "name": "left_writing_hand",
+ "unicode": "1F58E",
+ "digest": "c4fc18ece6778339ebe14438aaf570e22385c3010c2d341824fa72ac6068cfeb"
+ },
+ {
"name": "writing_hand_tone1",
"unicode": "270D-1F3FB",
"digest": "38e64e6dca4847a12aef8a117c113b2025d841501c4bc8188c57d0c8a4f1e34d"
@@ -8590,6 +11070,11 @@
"digest": "8396249161b6d865861b56aabd17cae2c821b0d814f4249bf8cab0bb21fa8ee9"
},
{
+ "name": "zipper_mouth_face",
+ "unicode": "1F910",
+ "digest": "8396249161b6d865861b56aabd17cae2c821b0d814f4249bf8cab0bb21fa8ee9"
+ },
+ {
"name": "zzz",
"unicode": "1F4A4",
"digest": "f07c56d2d55c0a886c26a8e3d49a9adeab54cc1a0c0354ea8d3bf23aaed3176d"
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 939469b3886..60b9f5e0ece 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -263,14 +263,19 @@ module API
expose :id, :path, :kind
end
- class ProjectAccess < Grape::Entity
+ class Member < Grape::Entity
expose :access_level
- expose :notification_level
+ expose :notification_level do |member, options|
+ if member.notification_setting
+ NotificationSetting.levels[member.notification_setting.level]
+ end
+ end
end
- class GroupAccess < Grape::Entity
- expose :access_level
- expose :notification_level
+ class ProjectAccess < Member
+ end
+
+ class GroupAccess < Member
end
class ProjectService < Grape::Entity
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index c165de21a75..91e420832f3 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -23,8 +23,10 @@ module API
# Create group. Available only for users who can create groups.
#
# Parameters:
- # name (required) - The name of the group
- # path (required) - The path of the group
+ # name (required) - The name of the group
+ # path (required) - The path of the group
+ # description (optional) - The description of the group
+ # visibility_level (optional) - The visibility level of the group
# Example Request:
# POST /groups
post do
@@ -42,6 +44,28 @@ module API
end
end
+ # Update group. Available only for users who can administrate groups.
+ #
+ # Parameters:
+ # id (required) - The ID of a group
+ # path (optional) - The path of the group
+ # description (optional) - The description of the group
+ # visibility_level (optional) - The visibility level of the group
+ # Example Request:
+ # PUT /groups/:id
+ put ':id' do
+ group = find_group(params[:id])
+ authorize! :admin_group, group
+
+ attrs = attributes_for_keys [:name, :path, :description, :visibility_level]
+
+ if ::Groups::UpdateService.new(group, current_user, attrs).execute
+ present group, with: Entities::GroupDetail
+ else
+ render_validation_error!(group)
+ end
+ end
+
# Get a single group, with containing projects
#
# Parameters:
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 4921ae99e78..96af7d7675c 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -91,8 +91,7 @@ module API
if can?(current_user, :read_group, group)
group
else
- forbidden!("#{current_user.username} lacks sufficient "\
- "access to #{group.name}")
+ not_found!('Group')
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index c4ea05ee6cf..850e99981ff 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -195,6 +195,29 @@ module API
end
end
+ # Move an existing issue
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # issue_id (required) - The ID of a project issue
+ # to_project_id (required) - The ID of the new project
+ # Example Request:
+ # POST /projects/:id/issues/:issue_id/move
+ post ':id/issues/:issue_id/move' do
+ required_attributes! [:to_project_id]
+
+ issue = user_project.issues.find(params[:issue_id])
+ new_project = Project.find(params[:to_project_id])
+
+ begin
+ issue = ::Issues::MoveService.new(user_project, current_user).execute(issue, new_project)
+ present issue, with: Entities::Issue, current_user: current_user
+ rescue ::Issues::MoveService::MoveError => error
+ render_api_error!(error.message, 400)
+ end
+ end
+
+ #
# Delete a project issue
#
# Parameters:
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 174473f5371..a1c98f5e8ff 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -112,6 +112,23 @@ module API
end
end
+ # Delete a +noteable+ note
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # noteable_id (required) - The ID of an issue, MR, or snippet
+ # node_id (required) - The ID of a note
+ # Example Request:
+ # DELETE /projects/:id/issues/:noteable_id/notes/:note_id
+ # DELETE /projects/:id/snippets/:noteable_id/notes/:node_id
+ delete ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
+ note = user_project.notes.find(params[:note_id])
+ authorize! :admin_note, note
+
+ ::Notes::DeleteService.new(user_project, current_user).execute(note)
+
+ present note, with: Entities::Note
+ end
end
end
end
diff --git a/lib/api/project_members.rb b/lib/api/project_members.rb
index c756bb479fc..4aefdf319c6 100644
--- a/lib/api/project_members.rb
+++ b/lib/api/project_members.rb
@@ -93,12 +93,17 @@ module API
# Example Request:
# DELETE /projects/:id/members/:user_id
delete ":id/members/:user_id" do
- authorize! :admin_project, user_project
project_member = user_project.project_members.find_by(user_id: params[:user_id])
- unless project_member.nil?
- project_member.destroy
- else
+
+ unless current_user.can?(:admin_project, user_project) ||
+ current_user.can?(:destroy_project_member, project_member)
+ forbidden!
+ end
+
+ if project_member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
+ else
+ project_member.destroy
end
end
end
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 2d8a9e51bb9..d1a10479e44 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -16,6 +16,20 @@ module API
with: Entities::RepoTag, project: user_project
end
+ # Get a single repository tag
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # tag_name (required) - The name of the tag
+ # Example Request:
+ # GET /projects/:id/repository/tags/:tag_name
+ get ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do
+ tag = user_project.repository.find_tag(params[:tag_name])
+ not_found!('Tag') unless tag
+
+ present tag, with: Entities::RepoTag, project: user_project
+ end
+
# Create tag
#
# Parameters:
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index 6108697bc20..7479e729db1 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -1,4 +1,7 @@
require 'gitlab/git'
module Gitlab
+ def self.com?
+ Gitlab.config.gitlab.url == 'https://gitlab.com'
+ end
end
diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb
index 2a0a5629be5..484970c5a10 100644
--- a/lib/gitlab/metrics.rb
+++ b/lib/gitlab/metrics.rb
@@ -104,6 +104,16 @@ module Gitlab
retval
end
+ # Adds a tag to the current transaction (if any)
+ #
+ # name - The name of the tag to add.
+ # value - The value of the tag.
+ def self.tag_transaction(name, value)
+ trans = current_transaction
+
+ trans.add_tag(name, value) if trans
+ end
+
# When enabled this should be set before being used as the usual pattern
# "@foo ||= bar" is _not_ thread-safe.
if enabled?
diff --git a/lib/gitlab/saml/user.rb b/lib/gitlab/saml/user.rb
index c1072452abe..dba4bbfc899 100644
--- a/lib/gitlab/saml/user.rb
+++ b/lib/gitlab/saml/user.rb
@@ -26,7 +26,7 @@ module Gitlab
@user ||= build_new_user
end
- if external_users_enabled?
+ if external_users_enabled? && @user
# Check if there is overlap between the user's groups and the external groups
# setting then set user as external or internal.
if (auth_hash.groups & Gitlab::Saml::Config.external_groups).empty?
@@ -48,6 +48,7 @@ module Gitlab
end
def changed?
+ return true unless gl_user
gl_user.changed? || gl_user.identities.any?(&:changed?)
end
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
index 7ec00a898fd..030ee8bafcb 100644
--- a/lib/tasks/gemojione.rake
+++ b/lib/tasks/gemojione.rake
@@ -5,12 +5,23 @@ namespace :gemojione do
require 'json'
dir = Gemojione.index.images_path
+ digests = []
+ aliases = Hash.new { |hash, key| hash[key] = [] }
+ aliases_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
- digests = AwardEmoji.emojis.map do |name, emoji_hash|
+ JSON.parse(File.read(aliases_path)).each do |alias_name, real_name|
+ aliases[real_name] << alias_name
+ end
+
+ AwardEmoji.emojis.map do |name, emoji_hash|
fpath = File.join(dir, "#{emoji_hash['unicode']}.png")
digest = Digest::SHA256.file(fpath).hexdigest
- { name: name, unicode: emoji_hash['unicode'], digest: digest }
+ digests << { name: name, unicode: emoji_hash['unicode'], digest: digest }
+
+ aliases[name].each do |alias_name|
+ digests << { name: alias_name, unicode: emoji_hash['unicode'], digest: digest }
+ end
end
out = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json')
diff --git a/spec/controllers/groups/notification_settings_controller_spec.rb b/spec/controllers/groups/notification_settings_controller_spec.rb
new file mode 100644
index 00000000000..0786e45515a
--- /dev/null
+++ b/spec/controllers/groups/notification_settings_controller_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Groups::NotificationSettingsController do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ describe '#update' do
+ context 'when not authorized' do
+ it 'redirects to sign in page' do
+ put :update,
+ group_id: group.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ put :update,
+ group_id: group.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response.status).to eq 200
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 75e6b6f45a7..c54e83339a1 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -157,6 +157,34 @@ describe Projects::MergeRequestsController do
end
end
+ describe 'PUT #update' do
+ context 'there is no source project' do
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:forked_project_with_submodules) }
+ let(:merge_request) { create(:merge_request, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
+
+ before do
+ fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
+ fork_project.save
+ merge_request.reload
+ fork_project.destroy
+ end
+
+ it 'closes MR without errors' do
+ post :update,
+ namespace_id: project.namespace.path,
+ project_id: project.path,
+ id: merge_request.iid,
+ merge_request: {
+ state_event: 'close'
+ }
+
+ expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request])
+ expect(merge_request.reload.closed?).to be_truthy
+ end
+ end
+ end
+
describe "DELETE #destroy" do
it "denies access to users unless they're admin or project owner" do
delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid
diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb
new file mode 100644
index 00000000000..4908b545648
--- /dev/null
+++ b/spec/controllers/projects/notification_settings_controller_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Projects::NotificationSettingsController do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ describe '#update' do
+ context 'when not authorized' do
+ it 'redirects to sign in page' do
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response.status).to eq 200
+ end
+ end
+ end
+end
diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb
new file mode 100644
index 00000000000..9e007ab7635
--- /dev/null
+++ b/spec/features/merge_requests/edit_mr_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+feature 'Edit Merge Request', feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, :with_diffs, source_project: project) }
+
+ before do
+ project.team << [user, :master]
+
+ login_as user
+
+ visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ context 'editing a MR' do
+ it 'form should have class js-quick-submit' do
+ expect(page).to have_selector('.js-quick-submit')
+ end
+ end
+end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index ed97b6cb577..782c0bfe666 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -100,8 +100,7 @@ feature 'Project', feature: true do
it 'click toggle and show dropdown', js: true do
find('.js-projects-dropdown-toggle').click
- wait_for_ajax
- expect(page).to have_css('.select2-results li', count: 1)
+ expect(page).to have_css('.dropdown-menu-projects .dropdown-content li', count: 1)
end
end
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index f1aba4cfdf3..9d5f009ebe1 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -2,34 +2,15 @@ require 'spec_helper'
describe NotificationsHelper do
describe 'notification_icon' do
- let(:notification) { double(disabled?: false, participating?: false, watch?: false) }
-
- context "disabled notification" do
- before { allow(notification).to receive(:disabled?).and_return(true) }
-
- it "has a red icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-off ns-mute"')
- end
- end
-
- context "participating notification" do
- before { allow(notification).to receive(:participating?).and_return(true) }
-
- it "has a blue icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-down ns-part"')
- end
- end
-
- context "watched notification" do
- before { allow(notification).to receive(:watch?).and_return(true) }
-
- it "has a green icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-up ns-watch"')
- end
- end
+ it { expect(notification_icon(:disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
+ it { expect(notification_icon(:participating)).to match('class="fa fa-volume-up fa-fw"') }
+ it { expect(notification_icon(:mention)).to match('class="fa fa-at fa-fw"') }
+ it { expect(notification_icon(:global)).to match('class="fa fa-globe fa-fw"') }
+ it { expect(notification_icon(:watch)).to match('class="fa fa-eye fa-fw"') }
+ end
- it "has a blue icon" do
- expect(notification_icon(notification)).to match('class="fa fa-circle-o ns-default"')
- end
+ describe 'notification_title' do
+ it { expect(notification_title(:watch)).to match('Watch') }
+ it { expect(notification_title(:mention)).to match('On mention') }
end
end
diff --git a/spec/javascripts/fixtures/project_title.html.haml b/spec/javascripts/fixtures/project_title.html.haml
index e5850b62659..4547feeb212 100644
--- a/spec/javascripts/fixtures/project_title.html.haml
+++ b/spec/javascripts/fixtures/project_title.html.haml
@@ -1,7 +1,20 @@
-%h1.title
- %a
- GitLab Org
- %a.project-item-select-holder{href: "/gitlab-org/gitlab-test"}
- GitLab Test
- %input#project_path.project-item-select.js-projects-dropdown.ajax-project-select{type: "hidden", name: "project_path", "data-include-groups" => "false"}
- %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle
+.header-content
+ %h1.title
+ %a
+ GitLab Org
+ %a.project-item-select-holder{href: "/gitlab-org/gitlab-test"}
+ GitLab Test
+ %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle{ "data-toggle" => "dropdown", "data-target" => ".header-content" }
+ .js-dropdown-menu-projects
+ .dropdown-menu.dropdown-select.dropdown-menu-projects
+ .dropdown-title
+ %span Go to a project
+ %button.dropdown-title-button.dropdown-menu-close{"aria-label" => "Close", type: "button"}
+ %i.fa.fa-times.dropdown-menu-close-icon
+ .dropdown-input
+ %input.dropdown-input-field{id: "", placeholder: "Search your projects", type: "search", value: ""}
+ %i.fa.fa-search.dropdown-input-search
+ %i.fa.fa-times.dropdown-input-clear.js-dropdown-input-clear{role: "button"}
+ .dropdown-content
+ .dropdown-loading
+ %i.fa.fa-spinner.fa-spin
diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee
index 47c7b7febe3..3d8de2ff989 100644
--- a/spec/javascripts/project_title_spec.js.coffee
+++ b/spec/javascripts/project_title_spec.js.coffee
@@ -1,4 +1,6 @@
+#= require bootstrap
#= require select2
+#= require gl_dropdown
#= require api
#= require project_select
#= require project
@@ -14,9 +16,6 @@ describe 'Project Title', ->
fixture.load('project_title.html')
@project = new Project()
- spyOn(@project, 'changeProject').and.callFake (url) ->
- window.current_project_url = url
-
describe 'project list', ->
beforeEach =>
@projects_data = fixture.load('projects.json')[0]
@@ -29,18 +28,9 @@ describe 'Project Title', ->
it 'to show on toggle click', =>
$('.js-projects-dropdown-toggle').click()
-
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(true)
- expect($('.ajax-project-dropdown li').length).toBe(@projects_data.length)
+ expect($('.header-content').hasClass('open')).toBe(true)
it 'hide dropdown', ->
- $("#select2-drop-mask").click()
-
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false)
-
- it 'change project when clicking item', ->
- $('.js-projects-dropdown-toggle').click()
- $('.ajax-project-dropdown li:nth-child(2)').trigger('mouseup')
+ $(".dropdown-menu-close-icon").click()
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false)
- expect(window.current_project_url).toBe('http://localhost:3000/h5bp/html5-boilerplate')
+ expect($('.header-content').hasClass('open')).toBe(false)
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index 3dee13e27f4..10177c0e8dd 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -98,4 +98,29 @@ describe Gitlab::Metrics do
end
end
end
+
+ describe '.tag_transaction' do
+ context 'without a transaction' do
+ it 'does nothing' do
+ expect_any_instance_of(Gitlab::Metrics::Transaction).
+ not_to receive(:add_tag)
+
+ Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ end
+ end
+
+ context 'with a transaction' do
+ let(:transaction) { Gitlab::Metrics::Transaction.new }
+
+ it 'adds the tag to the transaction' do
+ expect(Gitlab::Metrics).to receive(:current_transaction).
+ and_return(transaction)
+
+ expect(transaction).to receive(:add_tag).
+ with(:foo, 'bar')
+
+ Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
new file mode 100644
index 00000000000..c59dfea5c55
--- /dev/null
+++ b/spec/lib/gitlab_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+describe Gitlab, lib: true do
+ describe '.com?' do
+ it 'is true when on GitLab.com' do
+ stub_config_setting(url: 'https://gitlab.com')
+
+ expect(described_class.com?).to eq true
+ end
+
+ it 'is false when not on GitLab.com' do
+ stub_config_setting(url: 'http://example.com')
+
+ expect(described_class.com?).to eq false
+ end
+ end
+end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
new file mode 100644
index 00000000000..295081e9da1
--- /dev/null
+++ b/spec/models/notification_setting_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+RSpec.describe NotificationSetting, type: :model do
+ describe "Associations" do
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:source) }
+ end
+
+ describe "Validation" do
+ subject { NotificationSetting.new(source_id: 1, source_type: 'Project') }
+
+ it { is_expected.to validate_presence_of(:user) }
+ it { is_expected.to validate_presence_of(:source) }
+ it { is_expected.to validate_presence_of(:level) }
+ it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) }
+ end
+end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 4e49c413f23..c3a4016fa49 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -393,6 +393,8 @@ describe Repository, models: true do
describe '#expire_cache' do
it 'expires all caches' do
expect(repository).to receive(:expire_branch_cache)
+ expect(repository).to receive(:expire_branch_count_cache)
+ expect(repository).to receive(:expire_tag_count_cache)
repository.expire_cache
end
diff --git a/spec/requests/api/group_members_spec.rb b/spec/requests/api/group_members_spec.rb
index 3e8b4aa1f88..96d89e69209 100644
--- a/spec/requests/api/group_members_spec.rb
+++ b/spec/requests/api/group_members_spec.rb
@@ -42,9 +42,10 @@ describe API::API, api: true do
end
end
- it "users not part of the group should get access error" do
+ it 'users not part of the group should get access error' do
get api("/groups/#{group_with_members.id}/members", stranger)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
end
@@ -165,12 +166,13 @@ describe API::API, api: true do
end
end
- describe "DELETE /groups/:id/members/:user_id" do
- context "when not a member of the group" do
+ describe 'DELETE /groups/:id/members/:user_id' do
+ context 'when not a member of the group' do
it "should not delete guest's membership of group_with_members" do
random_user = create(:user)
delete api("/groups/#{group_with_members.id}/members/#{owner.id}", random_user)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 41c9cacd455..37ddab83c30 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -61,7 +61,8 @@ describe API::API, api: true do
it "should not return a group not attached to user1" do
get api("/groups/#{group2.id}", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
@@ -92,9 +93,54 @@ describe API::API, api: true do
it 'should not return a group not attached to user1' do
get api("/groups/#{group2.path}", user1)
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ describe 'PUT /groups/:id' do
+ let(:new_group_name) { 'New Group'}
+
+ context 'when authenticated as the group owner' do
+ it 'updates the group' do
+ put api("/groups/#{group1.id}", user1), name: new_group_name
+
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(new_group_name)
+ end
+
+ it 'returns 404 for a non existing group' do
+ put api('/groups/1328', user1)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when authenticated as the admin' do
+ it 'updates the group' do
+ put api("/groups/#{group1.id}", admin), name: new_group_name
+
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(new_group_name)
+ end
+ end
+
+ context 'when authenticated as an user that can see the group' do
+ it 'does not updates the group' do
+ put api("/groups/#{group1.id}", user2), name: new_group_name
+
expect(response.status).to eq(403)
end
end
+
+ context 'when authenticated as an user that cannot see the group' do
+ it 'returns 404 when trying to update the group' do
+ put api("/groups/#{group2.id}", user1), name: new_group_name
+
+ expect(response.status).to eq(404)
+ end
+ end
end
describe "GET /groups/:id/projects" do
@@ -113,7 +159,8 @@ describe API::API, api: true do
it "should not return a group not attached to user1" do
get api("/groups/#{group2.id}/projects", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
@@ -145,7 +192,8 @@ describe API::API, api: true do
it 'should not return a group not attached to user1' do
get api("/groups/#{group2.path}/projects", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
end
@@ -203,7 +251,8 @@ describe API::API, api: true do
it "should not remove a group not attached to user1" do
delete api("/groups/#{group2.id}", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 822d3ad3017..3d7a31cbb6a 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -7,7 +7,7 @@ describe API::API, api: true do
let(:author) { create(:author) }
let(:assignee) { create(:assignee) }
let(:admin) { create(:user, :admin) }
- let!(:project) { create(:project, :public, namespace: user.namespace ) }
+ let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
let!(:closed_issue) do
create :closed_issue,
author: user,
@@ -501,4 +501,72 @@ describe API::API, api: true do
end
end
end
+
+ describe '/projects/:id/issues/:issue_id/move' do
+ let!(:target_project) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace ) }
+ let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace ) }
+
+ it 'moves an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(201)
+ expect(json_response['project_id']).to eq(target_project.id)
+ end
+
+ context 'when source and target projects are the same' do
+ it 'returns 400 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: project.id
+
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Cannot move issue to project it originates from!')
+ end
+ end
+
+ context 'when the user does not have the permission to move issues' do
+ it 'returns 400 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: target_project2.id
+
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Cannot move issue due to insufficient permissions!')
+ end
+ end
+
+ it 'moves the issue to another namespace if I am admin' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", admin),
+ to_project_id: target_project2.id
+
+ expect(response.status).to eq(201)
+ expect(json_response['project_id']).to eq(target_project2.id)
+ end
+
+ context 'when issue does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/123/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when source project does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/123/issues/#{issue.id}/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when target project does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: 123
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 39f9a06fe1b..a467bc935af 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -241,4 +241,65 @@ describe API::API, api: true do
end
end
+ describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
+ context 'when noteable is an Issue' do
+ it 'deletes a note' do
+ delete api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user)
+
+ expect(response.status).to eq(200)
+ # Check if note is really deleted
+ delete api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user)
+ expect(response.status).to eq(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when noteable is a Snippet' do
+ it 'deletes a note' do
+ delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/#{snippet_note.id}", user)
+
+ expect(response.status).to eq(200)
+ # Check if note is really deleted
+ delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/#{snippet_note.id}", user)
+ expect(response.status).to eq(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/123", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when noteable is a Merge Request' do
+ it 'deletes a note' do
+ delete api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/#{merge_request_note.id}", user)
+
+ expect(response.status).to eq(200)
+ # Check if note is really deleted
+ delete api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/#{merge_request_note.id}", user)
+ expect(response.status).to eq(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/123", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
end
diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb
index 4301588b16a..c112ca5e3ca 100644
--- a/spec/requests/api/project_members_spec.rb
+++ b/spec/requests/api/project_members_spec.rb
@@ -118,8 +118,10 @@ describe API::API, api: true do
end
describe "DELETE /projects/:id/members/:user_id" do
- before { project_member }
- before { project_member2 }
+ before do
+ project_member
+ project_member2
+ end
it "should remove user from project team" do
expect do
@@ -132,6 +134,7 @@ describe API::API, api: true do
expect do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
end.to_not change { ProjectMember.count }
+ expect(response.status).to eq(200)
end
it "should return 200 if team member already removed" do
@@ -145,8 +148,19 @@ describe API::API, api: true do
delete api("/projects/#{project.id}/members/1000000", user)
end.to change { ProjectMember.count }.by(0)
expect(response.status).to eq(200)
- expect(json_response['message']).to eq("Access revoked")
expect(json_response['id']).to eq(1000000)
+ expect(json_response['message']).to eq('Access revoked')
+ end
+
+ context 'when the user is not an admin or owner' do
+ it 'can leave the project' do
+ expect do
+ delete api("/projects/#{project.id}/members/#{user3.id}", user3)
+ end.to change { ProjectMember.count }.by(-1)
+
+ expect(response.status).to eq(200)
+ expect(json_response['id']).to eq(project_member2.id)
+ end
end
end
end
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index a15be07ed57..9f9c3b1cf4c 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -40,6 +40,23 @@ describe API::API, api: true do
end
end
+ describe 'GET /projects/:id/repository/tags/:tag_name' do
+ let(:tag_name) { project.repository.tag_names.sort.reverse.first }
+
+ it 'returns a specific tag' do
+ get api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(tag_name)
+ end
+
+ it 'returns 404 for an invalid tag name' do
+ get api("/projects/#{project.id}/repository/tags/foobar", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
describe 'POST /projects/:id/repository/tags' do
context 'lightweight tags' do
it 'should create a new tag' do
diff --git a/spec/services/notes/delete_service_spec.rb b/spec/services/notes/delete_service_spec.rb
new file mode 100644
index 00000000000..1d0a747a480
--- /dev/null
+++ b/spec/services/notes/delete_service_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe Notes::DeleteService, services: true do
+ describe '#execute' do
+ it 'deletes a note' do
+ project = create(:empty_project)
+ issue = create(:issue, project: project)
+ note = create(:note, project: project, noteable: issue)
+
+ described_class.new(project, note.author).execute(note)
+
+ expect(project.issues.find(issue.id).notes).not_to include(note)
+ end
+ end
+end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 0f2aa3ae73c..d7c72dc0811 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -88,12 +88,9 @@ describe NotificationService, services: true do
note.project.namespace_id = group.id
note.project.group.add_user(@u_watcher, GroupMember::MASTER)
note.project.save
- user_project = note.project.project_members.find_by_user_id(@u_watcher.id)
- user_project.notification_level = Notification::N_PARTICIPATING
- user_project.save
- group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id)
- group_member.notification_level = Notification::N_GLOBAL
- group_member.save
+
+ @u_watcher.notification_settings_for(note.project).participating!
+ @u_watcher.notification_settings_for(note.project.group).global!
ActionMailer::Base.deliveries.clear
end
@@ -215,7 +212,7 @@ describe NotificationService, services: true do
end
it do
- @u_committer.update_attributes(notification_level: Notification::N_MENTION)
+ @u_committer.update_attributes(notification_level: :mention)
notification.new_note(note)
should_not_email(@u_committer)
end
@@ -246,7 +243,7 @@ describe NotificationService, services: true do
end
it do
- issue.assignee.update_attributes(notification_level: Notification::N_MENTION)
+ issue.assignee.update_attributes(notification_level: :mention)
notification.new_issue(issue, @u_disabled)
should_not_email(issue.assignee)
@@ -596,13 +593,13 @@ describe NotificationService, services: true do
end
def build_team(project)
- @u_watcher = create(:user, notification_level: Notification::N_WATCH)
- @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
- @u_participant_mentioned = create(:user, username: 'participant', notification_level: Notification::N_PARTICIPATING)
- @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
- @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION)
+ @u_watcher = create(:user, notification_level: :watch)
+ @u_participating = create(:user, notification_level: :participating)
+ @u_participant_mentioned = create(:user, username: 'participant', notification_level: :participating)
+ @u_disabled = create(:user, notification_level: :disabled)
+ @u_mentioned = create(:user, username: 'mention', notification_level: :mention)
@u_committer = create(:user, username: 'committer')
- @u_not_mentioned = create(:user, username: 'regular', notification_level: Notification::N_PARTICIPATING)
+ @u_not_mentioned = create(:user, username: 'regular', notification_level: :participating)
@u_outsider_mentioned = create(:user, username: 'outsider')
project.team << [@u_watcher, :master]
@@ -617,8 +614,8 @@ describe NotificationService, services: true do
def add_users_with_subscription(project, issuable)
@subscriber = create :user
@unsubscriber = create :user
- @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: Notification::N_PARTICIPATING)
- @watcher_and_subscriber = create(:user, notification_level: Notification::N_WATCH)
+ @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: :participating)
+ @watcher_and_subscriber = create(:user, notification_level: :watch)
project.team << [@subscribed_participant, :master]
project.team << [@subscriber, :master]
diff --git a/vendor/assets/javascripts/date.format.js b/vendor/assets/javascripts/date.format.js
new file mode 100644
index 00000000000..f5dc4abcd80
--- /dev/null
+++ b/vendor/assets/javascripts/date.format.js
@@ -0,0 +1,125 @@
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ *
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+
+var dateFormat = function () {
+ var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+ timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+ timezoneClip = /[^-+\dA-Z]/g,
+ pad = function (val, len) {
+ val = String(val);
+ len = len || 2;
+ while (val.length < len) val = "0" + val;
+ return val;
+ };
+
+ // Regexes and supporting functions are cached through closure
+ return function (date, mask, utc) {
+ var dF = dateFormat;
+
+ // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+ if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+ mask = date;
+ date = undefined;
+ }
+
+ // Passing date through Date applies Date.parse, if necessary
+ date = date ? new Date(date) : new Date;
+ if (isNaN(date)) throw SyntaxError("invalid date");
+
+ mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+ // Allow setting the utc argument via the mask
+ if (mask.slice(0, 4) == "UTC:") {
+ mask = mask.slice(4);
+ utc = true;
+ }
+
+ var _ = utc ? "getUTC" : "get",
+ d = date[_ + "Date"](),
+ D = date[_ + "Day"](),
+ m = date[_ + "Month"](),
+ y = date[_ + "FullYear"](),
+ H = date[_ + "Hours"](),
+ M = date[_ + "Minutes"](),
+ s = date[_ + "Seconds"](),
+ L = date[_ + "Milliseconds"](),
+ o = utc ? 0 : date.getTimezoneOffset(),
+ flags = {
+ d: d,
+ dd: pad(d),
+ ddd: dF.i18n.dayNames[D],
+ dddd: dF.i18n.dayNames[D + 7],
+ m: m + 1,
+ mm: pad(m + 1),
+ mmm: dF.i18n.monthNames[m],
+ mmmm: dF.i18n.monthNames[m + 12],
+ yy: String(y).slice(2),
+ yyyy: y,
+ h: H % 12 || 12,
+ hh: pad(H % 12 || 12),
+ H: H,
+ HH: pad(H),
+ M: M,
+ MM: pad(M),
+ s: s,
+ ss: pad(s),
+ l: pad(L, 3),
+ L: pad(L > 99 ? Math.round(L / 10) : L),
+ t: H < 12 ? "a" : "p",
+ tt: H < 12 ? "am" : "pm",
+ T: H < 12 ? "A" : "P",
+ TT: H < 12 ? "AM" : "PM",
+ Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+ o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+ S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+ };
+
+ return mask.replace(token, function ($0) {
+ return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+ });
+ };
+}();
+
+// Some common format strings
+dateFormat.masks = {
+ "default": "ddd mmm dd yyyy HH:MM:ss",
+ shortDate: "m/d/yy",
+ mediumDate: "mmm d, yyyy",
+ longDate: "mmmm d, yyyy",
+ fullDate: "dddd, mmmm d, yyyy",
+ shortTime: "h:MM TT",
+ mediumTime: "h:MM:ss TT",
+ longTime: "h:MM:ss TT Z",
+ isoDate: "yyyy-mm-dd",
+ isoTime: "HH:MM:ss",
+ isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
+ isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+dateFormat.i18n = {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ]
+};
+
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+ return dateFormat(this, mask, utc);
+};