summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-04-13 15:47:18 +0200
committerKamil Trzcinski <ayufan@ayufan.eu>2016-04-13 15:47:18 +0200
commit4af0968c43d517a3d702658749b5117ba4b9e11a (patch)
treed62a15cbcae8e1d1af00208c28fd1b09d01140f1
parent872bbb9fe2a5fbb5195aa448b615191baae960d7 (diff)
parentf026e53c4df5b0b3bb7435c05d3c8662afe45881 (diff)
downloadgitlab-ce-4af0968c43d517a3d702658749b5117ba4b9e11a.tar.gz
Merge remote-tracking branch 'origin/master' into ci-commit-as-pipeline
-rw-r--r--CHANGELOG22
-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/labels_select.js.coffee2
-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/repositories_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb12
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb1
-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--app/views/shared/issuable/_label_dropdown.html.haml2
-rw-r--r--config/gitlab.yml.example19
-rw-r--r--config/initializers/1_settings.rb5
-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/labels.md40
-rw-r--r--doc/api/notes.md144
-rw-r--r--doc/api/projects.md6
-rw-r--r--doc/api/tags.md46
-rw-r--r--doc/ci/ssh_keys/README.md8
-rw-r--r--doc/install/installation.md10
-rw-r--r--doc/integration/omniauth.md23
-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.rb18
-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/milestones.rb2
-rw-r--r--lib/api/notes.rb17
-rw-r--r--lib/api/project_members.rb13
-rw-r--r--lib/api/repositories.rb1
-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/o_auth/user.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/issues/filter_issues_spec.rb31
-rw-r--r--spec/features/merge_requests/edit_mr_spec.rb21
-rw-r--r--spec/features/projects_spec.rb3
-rw-r--r--spec/helpers/issues_helper_spec.rb23
-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/o_auth/user_spec.rb37
-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/milestones_spec.rb8
-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
132 files changed, 4414 insertions, 526 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3561c541df0..5399e3e5b8b 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,28 +16,46 @@ 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)
- Allow SAML to handle external users based on user's information !3530
+ - Allow Omniauth providers to be marked as `external` !3657
- Add endpoints to archive or unarchive a project !3372
- Add links to CI setup documentation from project settings and builds pages
- 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/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index d1fe116397a..90385621879 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -218,7 +218,7 @@ class @LabelsSelect
selectable: true
toggleLabel: (selected) ->
- if selected and selected.title isnt 'Any Label'
+ if selected and selected.title?
selected.title
else
defaultLabel
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 da3a32a9f8e..2fcef6c430a 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -238,6 +238,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/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 5c7614cfbaf..bb7a6b6a5ab 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,7 +11,6 @@ class Projects::RepositoriesController < Projects::ApplicationController
end
def archive
- RepositoryArchiveCacheWorker.perform_async
headers.store(*Gitlab::Workhorse.send_git_archive(@project, params[:ref], params[:format]))
head :ok
rescue => ex
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/issues_helper.rb b/app/helpers/issues_helper.rb
index bcf8639c829..4cb8adcebad 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -52,6 +52,7 @@ module IssuesHelper
def milestone_options(object)
milestones = object.project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
+ milestones.unshift(object.milestone) if object.milestone.present? && object.milestone.closed?
milestones.unshift(Milestone::None)
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
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 a898f7ba337..9ffdcc59128 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 33869e215c9..6766e4d1afa 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 b9d589a4594..e48830115bc 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/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
index fd5e58c1f1f..f722e61eeac 100644
--- a/app/views/shared/issuable/_label_dropdown.html.haml
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -1,7 +1,7 @@
- if params[:label_name].present?
= hidden_field_tag(:label_name, params[:label_name])
.dropdown
- %button.dropdown-menu-toggle.js-label-select.js-filter-submit{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}}
+ %button.dropdown-menu-toggle.js-label-select.js-filter-submit.js-extra-options{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}}
%span.dropdown-toggle-text
= h(params[:label_name].presence || "Label")
= icon('chevron-down')
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 35c7c425a5a..b28fc5c8e01 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
@@ -156,6 +165,9 @@ production: &base
stuck_ci_builds_worker:
cron: "0 0 * * *"
+ # Remove outdated repository archives
+ repository_archive_cache_worker:
+ cron: "0 * * * *"
#
# 2. GitLab CI settings
@@ -304,6 +316,13 @@ production: &base
# (default: false)
auto_link_saml_user: false
+ # Set different Omniauth providers as external so that all users creating accounts
+ # via these providers will not be able to have access to internal projects. You
+ # will need to use the full name of the provider, like `google_oauth2` for Google.
+ # Refer to the examples below for the full names of the supported providers.
+ # (default: [])
+ external_providers: []
+
## Auth providers
# Uncomment the following lines and fill in the data of the auth provider you want to use
# If your favorite auth provider is not listed you can use others:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 72c4d8d61ce..287f99c724d 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -129,6 +129,7 @@ Settings['omniauth'] ||= Settingslogic.new({})
Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil?
Settings.omniauth['auto_sign_in_with_provider'] = false if Settings.omniauth['auto_sign_in_with_provider'].nil?
Settings.omniauth['allow_single_sign_on'] = false if Settings.omniauth['allow_single_sign_on'].nil?
+Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_providers'].nil?
Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil?
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
Settings.omniauth['auto_link_saml_user'] = false if Settings.omniauth['auto_link_saml_user'].nil?
@@ -190,6 +191,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'] ||= []
#
@@ -239,6 +241,9 @@ Settings['cron_jobs'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_ci_builds_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_ci_builds_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['stuck_ci_builds_worker']['job_class'] = 'StuckCiBuildsWorker'
+Settings.cron_jobs['repository_archive_cache_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['repository_archive_cache_worker']['cron'] ||= '0 * * * *'
+Settings.cron_jobs['repository_archive_cache_worker']['job_class'] = 'RepositoryArchiveCacheWorker'
#
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 e000e35fca8..90e238fcfe3 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -647,6 +647,18 @@ ActiveRecord::Schema.define(version: 20160412175417) 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/labels.md b/doc/api/labels.md
index 544e898b6aa..3730c07c5a7 100644
--- a/doc/api/labels.md
+++ b/doc/api/labels.md
@@ -23,42 +23,42 @@ Example response:
{
"name" : "bug",
"color" : "#d9534f",
- "description": "Bug reported by user"
+ "description": "Bug reported by user",
+ "open_issues_count": 1,
+ "closed_issues_count": 0,
+ "open_merge_requests_count": 1
},
{
"color" : "#d9534f",
"name" : "confirmed",
- "description": "Confirmed issue"
+ "description": "Confirmed issue",
+ "open_issues_count": 2,
+ "closed_issues_count": 5,
+ "open_merge_requests_count": 0
},
{
"name" : "critical",
"color" : "#d9534f",
- "description": "Criticalissue. Need fix ASAP"
- },
- {
- "color" : "#428bca",
- "name" : "discussion",
- "description": "Issue that needs further discussion"
+ "description": "Criticalissue. Need fix ASAP",
+ "open_issues_count": 1,
+ "closed_issues_count": 3,
+ "open_merge_requests_count": 1
},
{
"name" : "documentation",
"color" : "#f0ad4e",
- "description": "Issue about documentation"
+ "description": "Issue about documentation",
+ "open_issues_count": 1,
+ "closed_issues_count": 0,
+ "open_merge_requests_count": 2
},
{
"color" : "#5cb85c",
"name" : "enhancement",
- "description": "Enhancement proposal"
- },
- {
- "color" : "#428bca",
- "name" : "suggestion",
- "description": "Suggestion"
- },
- {
- "color" : "#f0ad4e",
- "name" : "support",
- "description": "Support issue"
+ "description": "Enhancement proposal",
+ "open_issues_count": 1,
+ "closed_issues_count": 0,
+ "open_merge_requests_count": 1
}
]
```
diff --git a/doc/api/notes.md b/doc/api/notes.md
index d4d63e825ab..2e0936f11b5 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -32,6 +32,7 @@ Parameters:
"created_at": "2013-09-30T13:46:01Z"
},
"created_at": "2013-10-02T09:22:45Z",
+ "updated_at": "2013-10-02T10:22:45Z",
"system": true,
"upvote": false,
"downvote": false,
@@ -51,6 +52,7 @@ Parameters:
"created_at": "2013-09-30T13:46:01Z"
},
"created_at": "2013-10-02T09:56:03Z",
+ "updated_at": "2013-10-02T09:56:03Z",
"system": true,
"upvote": false,
"downvote": false,
@@ -103,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
@@ -180,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
@@ -223,6 +319,7 @@ Parameters:
"created_at": "2013-09-30T13:46:01Z"
},
"created_at": "2013-10-02T08:57:14Z",
+ "updated_at": "2013-10-02T08:57:14Z",
"system": false,
"upvote": false,
"downvote": false,
@@ -259,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/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md
index d790015aca1..7f825e6a065 100644
--- a/doc/ci/ssh_keys/README.md
+++ b/doc/ci/ssh_keys/README.md
@@ -30,7 +30,7 @@ This is the universal solution which works with any type of executor
## SSH keys when using the Docker executor
You will first need to create an SSH key pair. For more information, follow the
-instructions to [generate an SSH key](../ssh/README.md).
+instructions to [generate an SSH key](../../ssh/README.md).
Then, create a new **Secret Variable** in your project settings on GitLab
following **Settings > Variables**. As **Key** add the name `SSH_PRIVATE_KEY`
@@ -63,7 +63,7 @@ before_script:
As a final step, add the _public_ key from the one you created earlier to the
services that you want to have an access to from within the build environment.
If you are accessing a private GitLab repository you need to add it as a
-[deploy key](../ssh/README.md#deploy-keys).
+[deploy key](../../ssh/README.md#deploy-keys).
That's it! You can now have access to private servers or repositories in your
build environment.
@@ -79,12 +79,12 @@ on, and use that key for all projects that are run on this machine.
First, you need to login to the server that runs your builds.
Then from the terminal login as the `gitlab-runner` user and generate the SSH
-key pair as described in the [SSH keys documentation](../ssh/README.md).
+key pair as described in the [SSH keys documentation](../../ssh/README.md).
As a final step, add the _public_ key from the one you created earlier to the
services that you want to have an access to from within the build environment.
If you are accessing a private GitLab repository you need to add it as a
-[deploy key](../ssh/README.md#deploy-keys).
+[deploy key](../../ssh/README.md#deploy-keys).
Once done, try to login to the remote server in order to accept the fingerprint:
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/integration/omniauth.md b/doc/integration/omniauth.md
index 25f35988305..cab329c0dec 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -120,6 +120,29 @@ OmniAuth provider for an existing user.
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
+## Configure OmniAuth Providers as External
+
+>**Note:**
+This setting was introduced with version 8.7 of GitLab
+
+You can define which OmniAuth providers you want to be `external` so that all users
+creating accounts via these providers will not be able to have access to internal
+projects. You will need to use the full name of the provider, like `google_oauth2`
+for Google. Refer to the examples for the full names of the supported providers.
+
+**For Omnibus installations**
+
+```ruby
+ gitlab_rails['omniauth_external_providers'] = ['twitter', 'google_oauth2']
+```
+
+**For installations from source**
+
+```yaml
+ omniauth:
+ external_providers: ['twitter', 'google_oauth2']
+```
+
## Using Custom Omniauth Providers
>**Note:**
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 d76b46b8836..60b9f5e0ece 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -212,7 +212,7 @@ module API
expose :note, as: :body
expose :attachment_identifier, as: :attachment
expose :author, using: Entities::UserBasic
- expose :created_at
+ expose :created_at, :updated_at
expose :system?, as: :system
expose :noteable_id, :noteable_type
# upvote? and downvote? are deprecated, always return false
@@ -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
@@ -301,6 +306,7 @@ module API
class Label < Grape::Entity
expose :name, :color, :description
+ expose :open_issues_count, :closed_issues_count, :open_merge_requests_count
end
class Compare < 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/milestones.rb b/lib/api/milestones.rb
index 0f3f505fa05..84b4d4cdd6d 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -21,6 +21,7 @@ module API
# state (optional) - Return "active" or "closed" milestones
# Example Request:
# GET /projects/:id/milestones
+ # GET /projects/:id/milestones?iid=42
# GET /projects/:id/milestones?state=active
# GET /projects/:id/milestones?state=closed
get ":id/milestones" do
@@ -28,6 +29,7 @@ module API
milestones = user_project.milestones
milestones = filter_milestones_state(milestones, params[:state])
+ milestones = filter_by_iid(milestones, params[:iid]) if params[:iid].present?
present paginate(milestones), with: Entities::Milestone
end
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/repositories.rb b/lib/api/repositories.rb
index 0d0f0d4616d..62161aadb9a 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -98,7 +98,6 @@ module API
authorize! :download_code, user_project
begin
- RepositoryArchiveCacheWorker.perform_async
header *Gitlab::Workhorse.send_git_archive(user_project, params[:sha], params[:format])
rescue
not_found!('File')
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/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index 832fb08a526..356e96fcbab 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -54,6 +54,12 @@ module Gitlab
@user ||= build_new_user
end
+ if external_provider? && @user
+ @user.external = true
+ elsif @user
+ @user.external = false
+ end
+
@user
end
@@ -113,6 +119,10 @@ module Gitlab
end
end
+ def external_provider?
+ Gitlab.config.omniauth.external_providers.include?(auth_hash.provider)
+ end
+
def block_after_signup?
if creating_linked_ldap_user?
ldap_config.block_auto_created_users
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/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 90822a8c123..69b22232f10 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -76,6 +76,37 @@ describe 'Filter issues', feature: true do
end
end
+ describe 'Filter issues for label from issues#index', js: true do
+ before do
+ visit namespace_project_issues_path(project.namespace, project)
+ find('.js-label-select').click
+ end
+
+ it 'should filter by any label' do
+ find('.dropdown-menu-labels a', text: 'Any Label').click
+ page.within '.labels-filter' do
+ expect(page).to have_content 'Any Label'
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content('Label')
+ end
+
+ it 'should filter by no label' do
+ find('.dropdown-menu-labels a', text: 'No Label').click
+ page.within '.labels-filter' do
+ expect(page).to have_content 'No Label'
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content('No Label')
+ end
+
+ it 'should filter by no label' do
+ find('.dropdown-menu-labels a', text: label.title).click
+ page.within '.labels-filter' do
+ expect(page).to have_content label.title
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content(label.title)
+ end
+ end
+
describe 'Filter issues for assignee and label from issues#index' do
before do
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/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index ffd8ebae029..543593cf389 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -80,7 +80,7 @@ describe IssuesHelper do
end
end
- describe '#url_for_new_issue' do
+ describe 'url_for_new_issue' do
let(:issues_url) { ext_project.external_issue_tracker.new_issue_url }
let(:ext_expected) do
issues_url.gsub(':project_id', ext_project.id.to_s)
@@ -117,7 +117,7 @@ describe IssuesHelper do
end
end
- describe "#merge_requests_sentence" do
+ describe "merge_requests_sentence" do
subject { merge_requests_sentence(merge_requests)}
let(:merge_requests) do
[ build(:merge_request, iid: 1), build(:merge_request, iid: 2),
@@ -127,7 +127,7 @@ describe IssuesHelper do
it { is_expected.to eq("!1, !2, or !3") }
end
- describe "#note_active_class" do
+ describe "note_active_class" do
before do
@note = create :note
@note1 = create :note
@@ -142,10 +142,25 @@ describe IssuesHelper do
end
end
- describe "#awards_sort" do
+ describe "awards_sort" do
it "sorts a hash so thumbsup and thumbsdown are always on top" do
data = { "thumbsdown" => "some value", "lifter" => "some value", "thumbsup" => "some value" }
expect(awards_sort(data).keys).to eq(["thumbsup", "thumbsdown", "lifter"])
end
end
+
+ describe "milestone_options" do
+ it "gets closed milestone from current issue" do
+ closed_milestone = create(:closed_milestone, project: project)
+ milestone1 = create(:milestone, project: project)
+ milestone2 = create(:milestone, project: project)
+ issue.update_attributes(milestone_id: closed_milestone.id)
+
+ options = milestone_options(issue)
+
+ expect(options).to have_selector('option[selected]', text: closed_milestone.title)
+ expect(options).to have_selector('option', text: milestone1.title)
+ expect(options).to have_selector('option', text: milestone2.title)
+ end
+ 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/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 3a769acfdc0..6727a83e58a 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -15,20 +15,20 @@ describe Gitlab::OAuth::User, lib: true do
end
let(:ldap_user) { Gitlab::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
- describe :persisted? do
+ describe '#persisted?' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
it "finds an existing user based on uid and provider (facebook)" do
expect( oauth_user.persisted? ).to be_truthy
end
- it "returns false if use is not found in database" do
+ it 'returns false if user is not found in database' do
allow(auth_hash).to receive(:uid).and_return('non-existing')
expect( oauth_user.persisted? ).to be_falsey
end
end
- describe :save do
+ describe '#save' do
def stub_omniauth_config(messages)
allow(Gitlab.config.omniauth).to receive_messages(messages)
end
@@ -40,8 +40,27 @@ describe Gitlab::OAuth::User, lib: true do
let(:provider) { 'twitter' }
describe 'signup' do
- shared_examples "to verify compliance with allow_single_sign_on" do
- context "with new allow_single_sign_on enabled syntax" do
+ shared_examples 'to verify compliance with allow_single_sign_on' do
+ context 'provider is marked as external' do
+ it 'should mark user as external' do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'], external_providers: ['twitter'])
+ oauth_user.save
+ expect(gl_user).to be_valid
+ expect(gl_user.external).to be_truthy
+ end
+ end
+
+ context 'provider was external, now has been removed' do
+ it 'should mark existing user internal' do
+ create(:omniauth_user, extern_uid: 'my-uid', provider: 'twitter', external: true)
+ stub_omniauth_config(allow_single_sign_on: ['twitter'], external_providers: ['facebook'])
+ oauth_user.save
+ expect(gl_user).to be_valid
+ expect(gl_user.external).to be_falsey
+ end
+ end
+
+ context 'with new allow_single_sign_on enabled syntax' do
before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
it "creates a user from Omniauth" do
@@ -67,16 +86,16 @@ describe Gitlab::OAuth::User, lib: true do
end
end
- context "with new allow_single_sign_on disabled syntax" do
+ context 'with new allow_single_sign_on disabled syntax' do
before { stub_omniauth_config(allow_single_sign_on: []) }
- it "throws an error" do
+ it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
end
- context "with old allow_single_sign_on disabled (Default)" do
+ context 'with old allow_single_sign_on disabled (Default)' do
before { stub_omniauth_config(allow_single_sign_on: false) }
- it "throws an error" do
+ it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
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/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index d97bf6d38ff..344f0fe0b7f 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -50,10 +50,12 @@ describe API::API, api: true do
end
it 'should return a project milestone by iid' do
- get api("/projects/#{project.id}/milestones?iid=#{milestone.iid}", user)
+ get api("/projects/#{project.id}/milestones?iid=#{closed_milestone.iid}", user)
+
expect(response.status).to eq 200
- expect(json_response.first['title']).to eq milestone.title
- expect(json_response.first['id']).to eq milestone.id
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq closed_milestone.title
+ expect(json_response.first['id']).to eq closed_milestone.id
end
it 'should return 401 error if user not authenticated' do
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);
+};